|
12 | 12 | # See the License for the specific language governing permissions and
|
13 | 13 | # limitations under the License.
|
14 | 14 |
|
| 15 | +import datetime |
15 | 16 | import sys
|
| 17 | +import time |
| 18 | + |
16 | 19 | # [START import_sdk]
|
17 | 20 | import firebase_admin
|
18 | 21 | # [END import_sdk]
|
@@ -289,6 +292,120 @@ def list_all_users():
|
289 | 292 | print 'User: ' + user.uid
|
290 | 293 | # [END list_all_users]
|
291 | 294 |
|
| 295 | +def create_session_cookie(flask, app): |
| 296 | + # [START session_login] |
| 297 | + @app.route('/sessionLogin', methods=['POST']) |
| 298 | + def session_login(): |
| 299 | + # Get the ID token sent by the client |
| 300 | + id_token = flask.request.json['idToken'] |
| 301 | + # Set session expiration to 5 days. |
| 302 | + expires_in = datetime.timedelta(days=5) |
| 303 | + try: |
| 304 | + # Create the session cookie. This will also verify the ID token in the process. |
| 305 | + # The session cookie will have the same claims as the ID token. |
| 306 | + session_cookie = auth.create_session_cookie(id_token, expires_in=expires_in) |
| 307 | + response = flask.jsonify({'status': 'success'}) |
| 308 | + # Set cookie policy for session cookie. |
| 309 | + expires = datetime.datetime.now() + expires_in |
| 310 | + response.set_cookie( |
| 311 | + 'session', session_cookie, expires=expires, httponly=True, secure=True) |
| 312 | + return response |
| 313 | + except auth.AuthError: |
| 314 | + return flask.abort(401, 'Failed to create a session cookie') |
| 315 | + # [END session_login] |
| 316 | + |
| 317 | +def check_auth_time(id_token, flask): |
| 318 | + # [START check_auth_time] |
| 319 | + # To ensure that cookies are set only on recently signed in users, check auth_time in |
| 320 | + # ID token before creating a cookie. |
| 321 | + try: |
| 322 | + decoded_claims = auth.verify_id_token(id_token) |
| 323 | + # Only process if the user signed in within the last 5 minutes. |
| 324 | + if time.time() - decoded_claims['auth_time'] < 5 * 60: |
| 325 | + expires_in = datetime.timedelta(days=5) |
| 326 | + expires = datetime.datetime.now() + expires_in |
| 327 | + session_cookie = auth.create_session_cookie(id_token, expires_in=expires_in) |
| 328 | + response = flask.jsonify({'status': 'success'}) |
| 329 | + response.set_cookie( |
| 330 | + 'session', session_cookie, expires=expires, httponly=True, secure=True) |
| 331 | + return response |
| 332 | + # User did not sign in recently. To guard against ID token theft, require |
| 333 | + # re-authentication. |
| 334 | + return flask.abort(401, 'Recent sign in required') |
| 335 | + except ValueError: |
| 336 | + return flask.abort(401, 'Invalid ID token') |
| 337 | + except auth.AuthError: |
| 338 | + return flask.abort(401, 'Failed to create a session cookie') |
| 339 | + # [END check_auth_time] |
| 340 | + |
| 341 | +def verfy_session_cookie(app, flask): |
| 342 | + def serve_content_for_user(decoded_claims): |
| 343 | + print 'Serving content with claims:', decoded_claims |
| 344 | + return flask.jsonify({'status': 'success'}) |
| 345 | + |
| 346 | + # [START session_verify] |
| 347 | + @app.route('/profile', methods=['POST']) |
| 348 | + def access_restricted_content(): |
| 349 | + session_cookie = flask.request.cookies.get('session') |
| 350 | + # Verify the session cookie. In this case an additional check is added to detect |
| 351 | + # if the user's Firebase session was revoked, user deleted/disabled, etc. |
| 352 | + try: |
| 353 | + decoded_claims = auth.verify_session_cookie(session_cookie, check_revoked=True) |
| 354 | + return serve_content_for_user(decoded_claims) |
| 355 | + except ValueError: |
| 356 | + # Session cookie is unavailable or invalid. Force user to login. |
| 357 | + return flask.redirect('/login') |
| 358 | + except auth.AuthError: |
| 359 | + # Session revoked. Force user to login. |
| 360 | + return flask.redirect('/login') |
| 361 | + # [END session_verify] |
| 362 | + |
| 363 | +def check_permissions(session_cookie, flask): |
| 364 | + def serve_content_for_admin(decoded_claims): |
| 365 | + print 'Serving content with claims:', decoded_claims |
| 366 | + return flask.jsonify({'status': 'success'}) |
| 367 | + |
| 368 | + # [START session_verify_with_permission_check] |
| 369 | + try: |
| 370 | + decoded_claims = auth.verify_session_cookie(session_cookie, check_revoked=True) |
| 371 | + # Check custom claims to confirm user is an admin. |
| 372 | + if decoded_claims.get('admin') is True: |
| 373 | + return serve_content_for_admin(decoded_claims) |
| 374 | + else: |
| 375 | + return flask.abort(401, 'Insufficient permissions') |
| 376 | + except ValueError: |
| 377 | + # Session cookie is unavailable or invalid. Force user to login. |
| 378 | + return flask.redirect('/login') |
| 379 | + except auth.AuthError: |
| 380 | + # Session revoked. Force user to login. |
| 381 | + return flask.redirect('/login') |
| 382 | + # [END session_verify_with_permission_check] |
| 383 | + |
| 384 | +def clear_session_cookie(app, flask): |
| 385 | + # [START session_clear] |
| 386 | + @app.route('/sessionLogout', methods=['POST']) |
| 387 | + def session_logout(): |
| 388 | + response = flask.make_response(flask.redirect('/login')) |
| 389 | + response.set_cookie('session', expires=0) |
| 390 | + return response |
| 391 | + # [END session_clear] |
| 392 | + |
| 393 | +def clear_session_cookie_and_revoke(app, flask): |
| 394 | + # [START session_clear_and_revoke] |
| 395 | + @app.route('/sessionLogout', methods=['POST']) |
| 396 | + def session_logout(): |
| 397 | + session_cookie = flask.request.cookies.get('session') |
| 398 | + try: |
| 399 | + decoded_claims = auth.verify_session_cookie(session_cookie) |
| 400 | + auth.revoke_refresh_tokens(decoded_claims['sub']) |
| 401 | + response = flask.make_response(flask.redirect('/login')) |
| 402 | + response.set_cookie('session', expires=0) |
| 403 | + return response |
| 404 | + except ValueError: |
| 405 | + return flask.redirect('/login') |
| 406 | + # [END session_clear_and_revoke] |
| 407 | + |
| 408 | + |
292 | 409 | initialize_sdk_with_service_account()
|
293 | 410 | initialize_sdk_with_application_default()
|
294 | 411 | #initialize_sdk_with_refresh_token()
|
|
0 commit comments