コード例 #1
0
def get_site_settings_values():
    sql = f'''
        select 	site_visibility,
                title,
                fontsize,
                selfurl,
                coloraccent,
                isdarkmode,
                description,
                copyright,
                websiteurl,
                brandmail,
                brandlogourl,
                faviconurl,
                appiconurl
        from settings.site_settings
    '''

    msg = {'body': {'action': 'run', 'queries': [sql]}}

    method, response = db_handler(msg)

    if method == 'ok':
        response_dict = response[0][1:-1]
        return ok(json.loads(response_dict))
    else:
        return internal_server_error()
コード例 #2
0
def handler(event, context) -> dict:
    del context  # unused

    try:
        refresh_token = get_refresh_token(event)
    except NotLoggedIn:
        return {
            'statusCode': 401,
            'body': "Not logged in",
        }
    except BadRequest as e:
        return bad_request('', e)
    except InternalServerError as e:
        return internal_server_error('', e)

    if 'domains' in refresh_token:  # delegated token with domain restrictions
        domains = refresh_token['domains']
    else:
        domains = get_domains()

    access_tokens = {}
    try:
        for domain in domains:
            access_tokens[domain] = access_token_from_refresh_token(
                refresh_token,
                domain,
            )
    except BadRequest as e:
        return bad_request('', e)

    return {
        'statusCode': 200,
        'headers': {
            'Content-Type': 'application/json',
        },
        'body': json.dumps(access_tokens),
    }
コード例 #3
0
def handler(event, context) -> dict:
    del context  # unused

    try:
        redirect_uri = event['queryStringParameters']['redirect_uri']
    except KeyError:
        return bad_request('', "No redirect_uri parameter found")

    redirect_uri_comp = urlsplit(redirect_uri)

    try:
        refresh_token = get_refresh_token(event)
    except NotLoggedIn:
        state = {
            'action': 'authorize',
            'redirect_uri': redirect_uri,
        }
        raw_state = jwt.encode(
            state,
            get_state_jwt_secret(),
            algorithm='HS256',
        )
        return redirect_to_cognito(state=raw_state)
    except BadRequest as e:
        return bad_request('', e)
    except InternalServerError as e:
        return internal_server_error('', e)

    # Is this domain allowed?
    if not is_allowed_domain(redirect_uri_comp.netloc):
        return bad_request('', f"{redirect_uri} is not an allowed domain")

    if 'domains' in refresh_token:  # delegated token with domain restrictions
        if redirect_uri_comp.netloc not in refresh_token['domains']:
            return bad_request(
                '',
                f"{redirect_uri} is not an allowed domain for this refresh token"
            )

    try:
        access_token = access_token_from_refresh_token(
            refresh_token, redirect_uri_comp.netloc)
    except BadRequest as e:
        return bad_request('', e)

    return {
        'statusCode': 302,
        'headers': {
            'Content-Type':
            'text/plain',
            'Location':
            urlunsplit((
                'https',
                redirect_uri_comp.netloc,
                get_config().set_cookie_path,
                urlencode({  # query
                    'access_token':
                    access_token,  # Key must match with λ@E's expectations
                    'redirect_uri':
                    redirect_uri,  # Key must match with λ@E's expectations
                }),
                '',  # fragment
            )),
        },
        'body': 'Redirecting...',
    }
コード例 #4
0
def handler(event, context) -> dict:
    del context  # unused

    try:
        refresh_token = get_refresh_token(event)
    except NotLoggedIn:
        state = {
            'action': 'delegate',
        }
        raw_state = jwt.encode(
            state,
            get_state_jwt_secret(),
            algorithm='HS256',
        )
        return redirect_to_cognito(state=raw_state)
    except BadRequest as e:
        return bad_request('', e)
    except InternalServerError as e:
        return internal_server_error('', e)

    if event['httpMethod'] == 'GET':
        structlog.get_logger().msg("Rendering index HTML")

        if 'domains' in refresh_token:
            # User wants to further narrow his access
            domains = refresh_token['domains']
            groups = {}
        else:
            domains = get_domains()

            groups = {}
            scan_paginator = dynamodb_client.get_paginator('scan')
            response_iterator = scan_paginator.paginate(
                TableName=get_config().group_table, )
            for page in response_iterator:
                for group_entry in page['Items']:
                    try:
                        groups[group_entry['group']
                               ['S']] = group_entry['domains']['SS']
                    except KeyError as e:
                        structlog.get_logger().msg(
                            "Invalid group in DynamoDB: " + repr(group_entry))
                        pass

        with open(os.path.join(os.path.dirname(__file__),
                               'delegate.html')) as f:
            html = f.read()
            html = html.replace('{{{domains}}}', json.dumps(domains)) \
                       .replace('{{{groups}}}', json.dumps(groups)) \
                       .replace('{{{use_grant_url}}}', json.dumps(f"https://{os.environ['DOMAIN_NAME']}/use_grant?grant="))

            return {
                'statusCode': 200,
                'headers': {
                    'Content-Type': 'text/html',
                },
                'body': html,
            }

    elif event['httpMethod'] == 'POST':
        structlog.get_logger().log("Validating POST request",
                                   body=event['body'])
        values = urllib.parse.parse_qs(event['body'], strict_parsing=True)
        structlog.get_logger().log("Decoded body", body=values)

        try:
            exp = int(values['exp'][0])
            del values['exp']

            subject = values['subject'][0]
            assert len(subject) > 0
            del values['subject']
        except (KeyError, AssertionError):
            return bad_request('mandatory fields not present')

        if exp > refresh_token['exp']:
            return bad_request('expiration too long')

        domains = set(values.keys())
        for domain in domains:
            if not re.match(r'^[a-zA-Z0-9.-]+$', domain):
                return bad_request(
                    '', f"`{domain}` does not look like a domain name")

            if not is_allowed_domain(domain):
                return bad_request('', 'Unknown domain in request')

        if 'domains' in refresh_token:
            if not domains.issubset(refresh_token['domains']):
                return bad_request('',
                                   'domain requested outside refresh_token')

        delegate_token = {
            'iat': int(time.time()),
            'exp': exp,
            'domains': list(domains),
            'azp': refresh_token['azp'],  # Authorized Party
            'sub': refresh_token.get('sub', []) + [subject],  # subject
        }
        structlog.get_logger().log("Issuing JWT", jwt=delegate_token)
        raw_delegate_token = jwt.encode(
            delegate_token,
            get_grant_jwt_secret(),
            algorithm='HS256',
        ).decode('ascii')

        return {
            'statusCode': 200,
            'headers': {
                'Content-Type': 'text/plain',
            },
            'body': raw_delegate_token,
        }
コード例 #5
0
def handler(event, context) -> dict:
    del context  # unused

    try:
        cognito_code = event['queryStringParameters']['code']
        state = event['queryStringParameters']['state']

    except (TypeError, KeyError):
        return bad_request('', 'missing required parameter')

    try:
        state = jwt.decode(
            state,
            get_state_jwt_secret(),
            algorithms=['HS256'],
        )
    except jwt.InvalidTokenError:
        return bad_request('', 'invalid state token')

    try:
        cognito_token = exchange_cognito_code(event, cognito_code)
    except BadRequest:
        return bad_request()
    except InternalServerError:
        return internal_server_error()

    # Issue a token valid for 180 days. This allows the user to issue delegate
    # tokens for up to this time.
    # But set the expiration of the Cookie itself to the validity of the
    # Cognito token.
    # Unless the user actively safeguards his cookie, he will have to
    # re-authenticate with Cognito. If this is malicious intend, the user
    # could delegate the same access to himself, and get the same result.
    now = int(time.time())
    refresh_token = {
        'iat': now,  # Issued AT
        'exp': now + 180 * 24 * 60 *
        60,  # EXPire: 180 days, maximum duration of delegated tokens
        'azp': cognito_token['cognito:username'],  # AuthoriZed Party
    }
    raw_refresh_token = jwt.encode(
        refresh_token,
        get_refresh_token_jwt_secret(),
        algorithm='HS256',
    ).decode('ascii')

    structlog.get_logger().msg(
        "Cognito Code exchanged succesfully, issuing refresh_token",
        refresh_token=refresh_token)  # Don't log signed token, only payload

    try:
        if state['action'] == 'index':
            location = f"https://{os.environ['DOMAIN_NAME']}/"
        elif state['action'] == 'delegate':
            location = f"https://{os.environ['DOMAIN_NAME']}/delegate"
        elif state['action'] == 'authorize':
            location = f"https://{os.environ['DOMAIN_NAME']}/authorize?" + \
                f"redirect_uri={urllib.parse.quote_plus(state['redirect_uri'])}"
        else:
            raise ValueError(f"Invalid action `{state['action']}`")
    except (KeyError, ValueError) as e:
        structlog.get_logger().msg("state is invalid", exception=e)
        return internal_server_error()

    return {
        'statusCode': 302,
        'headers': {
            'Content-Type':
            'text/plain',
            'Location':
            location,
            'Set-Cookie':
            generate_cookie(get_config().cookie_name_refresh_token,
                            raw_refresh_token,
                            max_age=int(cognito_token['exp'] - now)),
        },
        'body': 'Redirecting...',
    }
コード例 #6
0
def handler(event, context) -> dict:
    del context  # unused

    raw_refresh_token = None
    refresh_token_exp = None
    domains = None
    azp = None
    sub = []
    try:
        raw_refresh_token = get_raw_refresh_token(event)
        refresh_token = parse_raw_refresh_token(raw_refresh_token)

        refresh_token_exp = refresh_token['exp']
        azp = refresh_token['azp']  # Mandatory
        sub = refresh_token.get('sub', [])  # optional

        try:
            domains = refresh_token['domains']
        except KeyError:
            pass
    except (NotLoggedIn, BadRequest):
        pass
    except InternalServerError as e:
        return internal_server_error(
            'Something went wrong parsing the refresh token', e)

    state = {
        'action': 'index',
    }
    raw_state = jwt.encode(
        state,
        get_state_jwt_secret(),
        algorithm='HS256',
    )

    now = time.time()
    csrf = jwt.encode(
        {
            'iat': now,
            'sub': raw_refresh_token,
        },
        get_csrf_jwt_secret(),
        algorithm='HS256',
    ).decode('utf-8')

    with open(os.path.join(os.path.dirname(__file__), 'index.html')) as f:
        html = f.read()
        html = html.replace('{{{authenticate}}}', cognito_url(raw_state)) \
                   .replace('{{{refresh_token_exp}}}', json.dumps(refresh_token_exp)) \
                   .replace('{{{domains}}}', json.dumps(domains)) \
                   .replace('{{{azp}}}', json.dumps(azp)) \
                   .replace('{{{sub}}}', json.dumps(sub)) \
                   .replace('{{{csrf}}}', csrf)

        return {
            'statusCode': 200,
            'headers': {
                'Content-Type': 'text/html',
            },
            'body': html,
        }