Ejemplo n.º 1
0
def handler(event, _context):
    """Handle the request passed in.

    Keyword Args:
        event (Dict[str, Any]): The Lambda Event
    """
    request = event['Records'][0]['cf']['request']
    domain_name = request['headers']['host'][0]['value']
    querystring = request.get('querystring')
    request_query_string = ("?%s" % querystring) if querystring else ""
    requested_uri = '%s%s' % (request['uri'], request_query_string)
    nonce = generate_nonce()

    try:
        # Extract the cookies received from Cognito
        extracted = extract_and_parse_cookies(request['headers'],
                                              CONFIG['client_id'])
        token_user_name = extracted.get('tokenUserName')
        id_token = extracted.get('idToken')
        refresh_token = extracted.get('refreshToken')

        # If the token user name or id token are missing then we need
        # new credentials
        if not token_user_name or not id_token:
            msg = "No valid credentials present in cookies"
            LOGGER.error(msg)
            raise Exception(msg)

        # Get the expiration date from the id token.
        decoded_token = decode_token(id_token)
        expiration = decoded_token.get('exp')
        exp_date = datetime.datetime.fromtimestamp(expiration)
        now = datetime.datetime.now()

        # If we have a refresh token and the expiration date has passed
        # then forward the user to the refresh agent
        if now > exp_date and refresh_token:
            headers = {
                # Redirect the user to the refresh agent
                'location': [{
                    'key':
                    'location',
                    'value':
                    'https://%s%s?%s' %
                    (domain_name, CONFIG.get('redirect_path_auth_refresh'),
                     urlencode({
                         'requestedUri': requested_uri,
                         'nonce': nonce
                     }))
                }],
                'set-cookie': [
                    # Set the Nonce Cookie
                    {
                        'key':
                        'set-cookie',
                        'value':
                        'spa-auth-edge-nonce=%s; %s' %
                        (quote_plus(nonce),
                         CONFIG.get('cookie_settings').get('nonce'))
                    }
                ]
            }
            # Add all CloudFrontHeaders
            headers.update(CONFIG.get('cloud_front_headers'))
            return {
                'status': '307',
                'statusDescription': 'Temporary Redirect',
                'headers': headers
            }

        # Validate the token information against the Cognito JWKS
        validate_jwt(id_token, CONFIG.get('token_jwks_uri'),
                     CONFIG.get('token_issuer'), CONFIG.get('client_id'))

        return request
    # We need new authorization. Get the user over to Cognito
    except Exception:  # noqa pylint: disable=broad-except
        pkce, pkce_hash = generate_pkce_verifier()
        payload = {
            'redirect_uri':
            'https://%s%s' % (domain_name, CONFIG['redirect_path_sign_in']),
            'response_type':
            'code',
            'client_id':
            CONFIG["client_id"],
            'state':
            base64.urlsafe_b64encode(
                bytes(
                    json.dumps({
                        "nonce": nonce,
                        "requestedUri": requested_uri
                    }).encode())),
            'scope':
            " ".join(CONFIG['oauth_scopes']),
            'code_challenge_method':
            "S256",
            'code_challenge':
            pkce_hash
        }
        login_query_string = urlencode(payload, quote_via=quote_plus)
        headers = CONFIG.get('cloud_front_headers')
        headers['location'] = [{
            'key':
            'location',
            'value':
            'https://%s/oauth2/authorize?%s' %
            (CONFIG['cognito_auth_domain'], login_query_string)
        }]
        headers['set-cookie'] = [
            # Set Nonce Cookie
            {
                'key':
                'set-cookie',
                'value':
                'spa-auth-edge-nonce=%s; %s' %
                (quote_plus(nonce), CONFIG.get('cookie_settings',
                                               {}).get('nonce'))
            },
            # Set PKCE Cookie
            {
                'key':
                'set-cookie',
                'value':
                'spa-auth-edge-pkce=%s; %s' %
                (quote_plus(pkce), CONFIG.get('cookie_settings',
                                              {}).get('nonce'))
            },
        ]

        # Redirect user to the Cognito Login
        return {
            'status': '307',
            'statusDescription': 'Temporary Redirect',
            'headers': headers
        }
Ejemplo n.º 2
0
def handler(event, _context):
    """Handle the request passed in.

    Args:
        event (Dict[str, Any]): The Lambda Event.
        _context (Any): Lambda context object.

    """
    request = event["Records"][0]["cf"]["request"]
    domain_name = request["headers"]["host"][0]["value"]
    querystring = request.get("querystring")
    request_query_string = ("?%s" % querystring) if querystring else ""
    requested_uri = "%s%s" % (request["uri"], request_query_string)

    try:
        # Extract the cookies received from Cognito
        extracted = extract_and_parse_cookies(request["headers"],
                                              CONFIG["client_id"])
        token_user_name = extracted["token_user_name"]
        id_token = extracted["id_token"]
        refresh_token = extracted["refresh_token"]

        # If the token user name or id token are missing then we need
        # new credentials
        if not token_user_name or not id_token:
            msg = "No valid credentials present in cookies"
            LOGGER.error(msg)
            raise Exception(msg)

        # Get the expiration date from the id token.
        decoded_token = decode_token(id_token)
        expiration = decoded_token.get("exp")
        exp_date = datetime.datetime.fromtimestamp(expiration)
        now = datetime.datetime.now()

        # If we have a refresh token and the expiration date has passed
        # then forward the user to the refresh agent
        if now > (exp_date - datetime.timedelta(minutes=10)) and refresh_token:
            nonce = generate_nonce()
            response = {
                "status": "307",
                "statusDescription": "Temporary Redirect",
                "headers": {
                    # Redirect the user to the refresh agent
                    "location": [{
                        "key":
                        "location",
                        "value":
                        "https://%s%s?%s" % (
                            domain_name,
                            CONFIG.get("redirect_path_auth_refresh"),
                            urlencode({
                                "requestedUri": requested_uri,
                                "nonce": nonce
                            }),
                        ),
                    }],
                    "set-cookie": [
                        # Set the Nonce Cookie
                        {
                            "key":
                            "set-cookie",
                            "value":
                            "spa-auth-edge-nonce=%s; %s" % (
                                quote_plus(nonce),
                                CONFIG.get("cookie_settings").get("nonce"),
                            ),
                        },
                        {
                            "key":
                            "set-cookie",
                            "value":
                            "spa-auth-edge-nonce-hmac=%s; %s" % (
                                quote_plus(
                                    sign(nonce,
                                         CONFIG["nonce_signing_secret"])),
                                CONFIG.get("cookie_settings").get("nonce"),
                            ),
                        },
                    ],
                    **CONFIG.get("cloud_front_headers", {}),
                },
            }
            return response

        # Validate the token information against the Cognito JWKS
        validate_jwt(
            id_token,
            CONFIG["token_jwks_uri"],
            CONFIG["token_issuer"],
            CONFIG["client_id"],
        )

        return request
    except Exception:  # noqa pylint: disable=broad-except
        # We need new authorization. Get the user over to Cognito
        nonce = generate_nonce()
        state = {
            "nonce": nonce,
            "nonceHmac": sign(nonce, CONFIG["nonce_signing_secret"]),
            **generate_pkce_verifier(),
        }
        login_query_string = urlencode(
            {
                "redirect_uri":
                "https://%s%s" %
                (domain_name, CONFIG["redirect_path_sign_in"]),
                "response_type":
                "code",
                "client_id":
                CONFIG["client_id"],
                "state":
                base64.urlsafe_b64encode(
                    bytes(
                        json.dumps({
                            "nonce": state["nonce"],
                            "requestedUri": requested_uri
                        }).encode())),
                "scope":
                " ".join(CONFIG["oauth_scopes"]),
                "code_challenge_method":
                "S256",
                "code_challenge":
                state["pkceHash"],
            },
            quote_via=quote_plus,
        )
        # Redirect user to the Cognito Login
        response = {
            "status": "307",
            "statusDescription": "Temporary Redirect",
            "headers": {
                "location": [{
                    "key":
                    "location",
                    "value":
                    "https://%s/oauth2/authorize?%s" %
                    (CONFIG["cognito_auth_domain"], login_query_string),
                }],
                "set-cookie": [
                    {
                        "key":
                        "set-cookie",
                        "value":
                        "spa-auth-edge-nonce=%s; %s" % (
                            quote_plus(state["nonce"]),
                            CONFIG.get("cookie_settings", {}).get("nonce"),
                        ),
                    },
                    {
                        "key":
                        "set-cookie",
                        "value":
                        "spa-auth-edge-nonce-hmac=%s; %s" % (
                            quote_plus(state["nonceHmac"]),
                            CONFIG.get("cookie_settings", {}).get("nonce"),
                        ),
                    },
                    {
                        "key":
                        "set-cookie",
                        "value":
                        "spa-auth-edge-pkce=%s; %s" % (
                            quote_plus(state["pkce"]),
                            CONFIG.get("cookie_settings", {}).get("nonce"),
                        ),
                    },
                ],
                **CONFIG.get("cloud_front_headers", {}),
            },
        }
        return response