Ejemplo n.º 1
0
def keycloak():

    if not current_app.config['KEYCLOAK_URL']:
        return jsonify(status="error", message="Must define KEYCLOAK_URL setting in server configuration."), 503

    access_token_url = "{0}/auth/realms/{1}/protocol/openid-connect/token".format(current_app.config['KEYCLOAK_URL'], current_app.config['KEYCLOAK_REALM'])

    payload = {
        'client_id': request.json['clientId'],
        'client_secret': current_app.config['OAUTH2_CLIENT_SECRET'],
        'redirect_uri': request.json['redirectUri'],
        'grant_type': 'authorization_code',
        'code': request.json['code'],
    }

    try:
        r = requests.post(access_token_url, data=payload)
    except Exception:
        return jsonify(status="error", message="Failed to call Keycloak API over HTTPS")
    access_token = r.json()

    headers = {"Authorization": "{0} {1}".format(access_token['token_type'], access_token['access_token'])}
    r = requests.get("{0}/auth/realms/{1}/protocol/openid-connect/userinfo".format(current_app.config['KEYCLOAK_URL'], current_app.config['KEYCLOAK_REALM']), headers=headers)
    profile = r.json()

    roles = profile['roles']
    login = profile['preferred_username']

    if is_authorized('ALLOWED_KEYCLOAK_ROLES', roles):
        raise ApiError("User %s is not authorized" % login, 403)

    customer = get_customer(login, groups=roles)

    token = create_token(profile['sub'], profile['name'], login, provider='keycloak', customer=customer, roles=roles)
    return jsonify(token=token.tokenize)
Ejemplo n.º 2
0
def gitlab():

    access_token_url = current_app.config['GITLAB_URL'] + '/oauth/token'
    gitlab_api_url = current_app.config['GITLAB_URL'] + '/api/v3'

    payload = {
        'client_id': request.json['clientId'],
        'client_secret': current_app.config['OAUTH2_CLIENT_SECRET'],
        'redirect_uri': request.json['redirectUri'],
        'grant_type': 'authorization_code',
        'code': request.json['code'],
    }

    try:
        r = requests.post(access_token_url, data=payload)
    except Exception:
        return jsonify(status="error", message="Failed to call Gitlab API over HTTPS")
    access_token = r.json()

    r = requests.get(gitlab_api_url+'/user', params=access_token)
    profile = r.json()

    r = requests.get(gitlab_api_url+'/groups', params=access_token)
    groups = [g['path'] for g in r.json()]
    login = profile['username']

    if is_authorized('ALLOWED_GITLAB_GROUPS', groups):
        raise ApiError("User %s is not authorized" % login, 403)

    customer = get_customer(login, groups)

    token = create_token(profile['id'], profile.get('name', '@'+login), login, provider='gitlab', customer=customer,
                         groups=groups, email=profile.get('email', None), email_verified=True if profile.get('email', None) else False)
    return jsonify(token=token.tokenize)
Ejemplo n.º 3
0
def github():

    if current_app.config['GITHUB_URL']:
        access_token_url = current_app.config['GITHUB_URL'] + '/login/oauth/access_token'
        github_api_url = current_app.config['GITHUB_URL'] + '/api/v3'
    else:
        access_token_url = 'https://github.com/login/oauth/access_token'
        github_api_url = 'https://api.github.com'

    params = {
        'client_id': request.json['clientId'],
        'redirect_uri': request.json['redirectUri'],
        'client_secret': current_app.config['OAUTH2_CLIENT_SECRET'],
        'code': request.json['code']
    }

    headers = {'Accept': 'application/json'}
    r = requests.get(access_token_url, headers=headers, params=params)
    access_token = r.json()

    r = requests.get(github_api_url+'/user', params=access_token)
    profile = r.json()

    r = requests.get(github_api_url+'/user/orgs', params=access_token)  # list public and private Github orgs
    organizations = [o['login'] for o in r.json()]
    login = profile['login']

    if is_authorized('ALLOWED_GITHUB_ORGS', organizations):
        raise ApiError("User %s is not authorized" % login, 403)

    customer = get_customer(login, organizations)

    token = create_token(profile['id'], profile.get('name', '@'+login), login, provider='github', customer=customer,
                         orgs=organizations, email=profile.get('email', None), email_verified=True if 'email' in profile else False)
    return jsonify(token=token.tokenize)
Ejemplo n.º 4
0
def github():

    if current_app.config['GITHUB_URL']:
        access_token_url = current_app.config['GITHUB_URL'] + '/login/oauth/access_token'
        github_api_url = current_app.config['GITHUB_URL'] + '/api/v3'
    else:
        access_token_url = 'https://github.com/login/oauth/access_token'
        github_api_url = 'https://api.github.com'

    params = {
        'client_id': request.json['clientId'],
        'redirect_uri': request.json['redirectUri'],
        'client_secret': current_app.config['OAUTH2_CLIENT_SECRET'],
        'code': request.json['code']
    }

    headers = {'Accept': 'application/json'}
    r = requests.get(access_token_url, headers=headers, params=params)
    access_token = r.json()

    r = requests.get(github_api_url+'/user', params=access_token)
    profile = r.json()

    r = requests.get(github_api_url+'/user/orgs', params=access_token)  # list public and private Github orgs
    organizations = [o['login'] for o in r.json()]
    login = profile['login']

    if is_authorized('ALLOWED_GITHUB_ORGS', organizations):
        raise ApiError("User %s is not authorized" % login, 403)

    customer = get_customer(login, organizations)

    token = create_token(profile['id'], profile.get('name', '@'+login), login, provider='github', customer=customer,
                         orgs=organizations, email=profile.get('email', None), email_verified=True if 'email' in profile else False)
    return jsonify(token=token.tokenize)
Ejemplo n.º 5
0
def pingfederate():
    access_token_url = current_app.config['PINGFEDERATE_OPENID_ACCESS_TOKEN_URL']
    payload = {
        'client_id': request.json['clientId'],
        'client_secret': current_app.config['OAUTH2_CLIENT_SECRET'],
        'redirect_uri': request.json['redirectUri'],
        'grant_type': 'authorization_code',
        'code': request.json['code'],
        'scope': 'openid email',
    }

    try:
        r = requests.post(access_token_url, data=payload)
    except Exception:
        return jsonify(status="error", message="Failed to call sso API over HTTPS")
    access_token = r.json()
    encoded = access_token['access_token']
    keyfile = open (current_app.config['PINGFEDERATE_PUBKEY_LOCATION'], 'r')
    keystring = keyfile.read()
    decoded = jwt.decode(encoded, keystring, algorithms=current_app.config['PINGFEDERATE_TOKEN_ALGORITHM'])
    login = decoded[current_app.config['PINGFEDERATE_OPENID_PAYLOAD_USERNAME']]
    email = decoded[current_app.config['PINGFEDERATE_OPENID_PAYLOAD_EMAIL']]
    customer = get_customer(login, current_app.config['PINGFEDERATE_OPENID_PAYLOAD_GROUP'])
    token = create_token(login, email, email, provider='openid', customer=customer)
    return jsonify(token=token.tokenize)
Ejemplo n.º 6
0
def saml_response_from_idp():
    def _make_response(resp_obj, resp_code):
        if 'usePostMessage' in request.form.get(
                'RelayState', '') and 'text/html' in request.headers.get(
                    'Accept', ''):
            origins = current_app.config.get('CORS_ORIGINS', [])
            response = make_response(
                '''<!DOCTYPE html>
                    <html lang="en">
                        <head>
                            <meta charset="UTF-8">
                            <title>Authenticating...</title>
                            <script type="application/javascript">
                                var origins = {origins};
                                // in case when API and WebUI are on the same origin
                                if (origins.indexOf(window.location.origin) < 0)
                                    origins.push(window.location.origin);
                                // only one will succeed
                                origins.forEach(origin => window.opener.postMessage({msg_data}, origin));
                                window.close();
                            </script>
                        </head>
                        <body></body>
                    </html>'''.format(msg_data=json.dumps(resp_obj),
                                      origins=json.dumps(origins)), resp_code)
            response.headers['Content-Type'] = 'text/html'
            return response
        else:
            return jsonify(**resp_obj), resp_code

    authn_response = saml_client().parse_authn_request_response(
        request.form['SAMLResponse'], saml2.entity.BINDING_HTTP_POST)
    identity = authn_response.get_identity()
    email = identity['emailAddress'][0]
    domain = email.split('@')[1]
    name = (current_app.config.get(
        'SAML2_USER_NAME_FORMAT', '{givenName} {surname}')).format(
            **dict(map(lambda x: (x[0], x[1][0]), identity.items())))

    groups = identity.get('groups', [])
    if is_authorized('ALLOWED_SAML2_GROUPS', groups):
        return _make_response(
            {
                'status': 'error',
                'message': 'User {} is not authorized'.format(email)
            }, 403)

    customer = get_customer(email, groups=[domain])

    token = create_token(email,
                         name,
                         email,
                         provider='saml2',
                         customer=customer,
                         groups=groups)
    return _make_response({'status': 'ok', 'token': token.tokenize}, 200)
Ejemplo n.º 7
0
def keycloak():

    if not current_app.config['KEYCLOAK_URL']:
        return jsonify(
            status="error",
            message="Must define KEYCLOAK_URL setting in server configuration."
        ), 503

    access_token_url = "{0}/auth/realms/{1}/protocol/openid-connect/token".format(
        current_app.config['KEYCLOAK_URL'],
        current_app.config['KEYCLOAK_REALM'])

    payload = {
        'client_id': request.json['clientId'],
        'client_secret': current_app.config['OAUTH2_CLIENT_SECRET'],
        'redirect_uri': request.json['redirectUri'],
        'grant_type': 'authorization_code',
        'code': request.json['code'],
    }

    try:
        r = requests.post(access_token_url, data=payload)
    except Exception:
        return jsonify(status="error",
                       message="Failed to call Keycloak API over HTTPS")
    access_token = r.json()

    headers = {
        "Authorization":
        "{0} {1}".format(access_token['token_type'],
                         access_token['access_token'])
    }
    r = requests.get(
        "{0}/auth/realms/{1}/protocol/openid-connect/userinfo".format(
            current_app.config['KEYCLOAK_URL'],
            current_app.config['KEYCLOAK_REALM']),
        headers=headers)
    profile = r.json()

    roles = profile['roles']
    login = profile['preferred_username']

    if is_authorized('ALLOWED_KEYCLOAK_ROLES', roles):
        raise ApiError("User %s is not authorized" % login, 403)

    customer = get_customer(login, groups=roles)

    token = create_token(profile['sub'],
                         profile['name'],
                         login,
                         provider='keycloak',
                         customer=customer,
                         roles=roles)
    return jsonify(token=token.tokenize)
Ejemplo n.º 8
0
def saml_response_from_idp():
    def _make_response(resp_obj, resp_code):
        if 'usePostMessage' in request.form.get('RelayState', '') and 'text/html' in request.headers.get('Accept', ''):
            origins = current_app.config.get('CORS_ORIGINS', [])
            response = make_response(
                '''<!DOCTYPE html>
                    <html lang="en">
                        <head>
                            <meta charset="UTF-8">
                            <title>Authenticating...</title>
                            <script type="application/javascript">
                                var origins = {origins};
                                // in case when API and WebUI are on the same origin
                                if (origins.indexOf(window.location.origin) < 0)
                                    origins.push(window.location.origin);
                                // only one will succeed
                                origins.forEach(origin => window.opener.postMessage({msg_data}, origin));
                                window.close();
                            </script>
                        </head>
                        <body></body>
                    </html>'''.format(msg_data=json.dumps(resp_obj), origins=json.dumps(origins)),
                resp_code
            )
            response.headers['Content-Type'] = 'text/html'
            return response
        else:
            return jsonify(**resp_obj), resp_code

    authn_response = saml_client().parse_authn_request_response(
        request.form['SAMLResponse'],
        saml2.entity.BINDING_HTTP_POST
    )
    identity = authn_response.get_identity()
    email = identity['emailAddress'][0]
    domain = email.split('@')[1]
    name = (current_app.config.get('SAML2_USER_NAME_FORMAT', '{givenName} {surname}')).format(**dict(map(lambda x: (x[0], x[1][0]), identity.items())))

    groups = identity.get('groups', [])
    if is_authorized('ALLOWED_SAML2_GROUPS', groups):
        return _make_response({'status': 'error', 'message': 'User {} is not authorized'.format(email)}, 403)

    customer = get_customer(email, groups=[domain])

    token = create_token(email, name, email, provider='saml2', customer=customer, groups=groups)
    return _make_response({'status': 'ok', 'token': token.tokenize}, 200)
Ejemplo n.º 9
0
def google():
    access_token_url = 'https://accounts.google.com/o/oauth2/token'
    people_api_url = 'https://www.googleapis.com/plus/v1/people/me/openIdConnect'

    payload = {
        'client_id': request.json['clientId'],
        'client_secret': current_app.config['OAUTH2_CLIENT_SECRET'],
        'redirect_uri': request.json['redirectUri'],
        'grant_type': 'authorization_code',
        'code': request.json['code'],
    }
    r = requests.post(access_token_url, data=payload)
    token = r.json()

    id_token = Jwt.parse(token['id_token'],
                         key='',
                         verify=False,
                         algorithm='RS256')

    domain = id_token.email.split('@')[1]

    if is_authorized('ALLOWED_EMAIL_DOMAINS', groups=[domain]):
        raise ApiError("User %s is not authorized" % id_token.email, 403)

    # Get Google+ profile for Full name
    headers = {'Authorization': 'Bearer ' + token['access_token']}
    r = requests.get(people_api_url, headers=headers)
    profile = r.json()

    if not profile:
        raise ApiError("Google+ API is not enabled for this Client ID", 400)

    customer = get_customer(id_token.email, groups=[domain])

    name = profile.get('name', id_token.email.split('@')[0])
    token = create_token(id_token.subject,
                         name,
                         id_token.email,
                         provider='google',
                         customer=customer,
                         orgs=[domain],
                         email=id_token.email,
                         email_verified=id_token.email_verified)
    return jsonify(token=token.tokenize)
Ejemplo n.º 10
0
def login():
    # lookup user from username/email
    try:
        username = request.json.get('username', None) or request.json['email']
        password = request.json['password']
    except KeyError:
        raise ApiError("must supply 'username' and 'password'", 401)

    user = User.find_by_email(email=username)
    if not user:
        raise ApiError("invalid username or password", 401)

    if not user.verify_password(password):
        raise ApiError("invalid username or password", 401)

    # if email verification is enforced, deny login and send email
    if current_app.config['EMAIL_VERIFICATION'] and not user.email_verified:
        hash = str(uuid4())
        send_confirmation(user, hash)
        user.set_email_hash(hash)
        raise ApiError('email not verified', 401)

    # check user is active
    if user.status != 'active':
        raise ApiError('user not active', 403)

    # check allowed domain
    if is_authorized('ALLOWED_EMAIL_DOMAINS', groups=[user.domain]):
        raise ApiError("unauthorized domain", 403)

    # assign customer & update last login time
    customer = get_customer(user.email, groups=[user.domain])
    user.update_last_login()

    # generate token
    token = create_token(user.id,
                         user.name,
                         user.email,
                         provider='basic',
                         customer=customer,
                         roles=user.roles,
                         email=user.email,
                         email_verified=user.email_verified)
    return jsonify(token=token.tokenize)
Ejemplo n.º 11
0
def signup():
    try:
        user = User.parse(request.json)
    except Exception as e:
        raise ApiError(str(e), 400)

    # check allowed domain
    if is_authorized('ALLOWED_EMAIL_DOMAINS', groups=[user.domain]):
        raise ApiError("unauthorized domain", 403)

    if User.find_by_email(email=user.email):
        raise ApiError("username already exists", 409)

    try:
        user = user.create()
    except Exception as e:
        ApiError(str(e), 500)

    # if email verification is enforced, deny login and send email
    if current_app.config['EMAIL_VERIFICATION'] and not user.email_verified:
        hash = str(uuid4())
        send_confirmation(user, hash)
        user.set_email_hash(hash)
        raise ApiError('email not verified', 401)

    # check user is active
    if user.status != 'active':
        raise ApiError('user not active', 403)

    # assign customer & update last login time
    customer = get_customer(user.email, groups=[user.domain])
    user.update_last_login()

    # generate token
    token = create_token(user.id,
                         user.name,
                         user.email,
                         provider='basic',
                         customer=customer,
                         roles=user.roles,
                         email=user.email,
                         email_verified=user.email_verified)
    return jsonify(token=token.tokenize)
Ejemplo n.º 12
0
def gitlab():

    access_token_url = current_app.config['GITLAB_URL'] + '/oauth/token'
    gitlab_api_url = current_app.config['GITLAB_URL'] + '/api/v3'

    payload = {
        'client_id': request.json['clientId'],
        'client_secret': current_app.config['OAUTH2_CLIENT_SECRET'],
        'redirect_uri': request.json['redirectUri'],
        'grant_type': 'authorization_code',
        'code': request.json['code'],
    }

    try:
        r = requests.post(access_token_url, data=payload)
    except Exception:
        return jsonify(status="error",
                       message="Failed to call Gitlab API over HTTPS")
    access_token = r.json()

    r = requests.get(gitlab_api_url + '/user', params=access_token)
    profile = r.json()

    r = requests.get(gitlab_api_url + '/groups', params=access_token)
    groups = [g['path'] for g in r.json()]
    login = profile['username']

    if is_authorized('ALLOWED_GITLAB_GROUPS', groups):
        raise ApiError("User %s is not authorized" % login, 403)

    customer = get_customer(login, groups)

    token = create_token(
        profile['id'],
        profile.get('name', '@' + login),
        login,
        provider='gitlab',
        customer=customer,
        groups=groups,
        email=profile.get('email', None),
        email_verified=True if profile.get('email', None) else False)
    return jsonify(token=token.tokenize)
Ejemplo n.º 13
0
def login():
    # lookup user from username/email
    try:
        username = request.json.get('username', None) or request.json['email']
        password = request.json['password']
    except KeyError:
        raise ApiError("must supply 'username' and 'password'", 401)

    user = User.find_by_email(email=username)
    if not user:
        raise ApiError("invalid username or password", 401)

    if not user.verify_password(password):
        raise ApiError("invalid username or password", 401)

    # if email verification is enforced, deny login and send email
    if current_app.config['EMAIL_VERIFICATION'] and not user.email_verified:
        hash = str(uuid4())
        send_confirmation(user, hash)
        user.set_email_hash(hash)
        raise ApiError('email not verified', 401)

    # check user is active
    if user.status != 'active':
        raise ApiError('user not active', 403)

    # check allowed domain
    if is_authorized('ALLOWED_EMAIL_DOMAINS', groups=[user.domain]):
        raise ApiError("unauthorized domain", 403)

    # assign customer & update last login time
    customer = get_customer(user.email, groups=[user.domain])
    user.update_last_login()

    # generate token
    token = create_token(user.id, user.name, user.email, provider='basic', customer=customer,
                         roles=user.roles, email=user.email, email_verified=user.email_verified)
    return jsonify(token=token.tokenize)
Ejemplo n.º 14
0
def signup():
    try:
        user = User.parse(request.json)
    except Exception as e:
        raise ApiError(str(e), 400)

    # check allowed domain
    if is_authorized('ALLOWED_EMAIL_DOMAINS', groups=[user.domain]):
        raise ApiError("unauthorized domain", 403)

    if User.find_by_email(email=user.email):
        raise ApiError("username already exists", 409)

    try:
        user = user.create()
    except Exception as e:
        ApiError(str(e), 500)

    # if email verification is enforced, deny login and send email
    if current_app.config['EMAIL_VERIFICATION'] and not user.email_verified:
        hash = str(uuid4())
        send_confirmation(user, hash)
        user.set_email_hash(hash)
        raise ApiError('email not verified', 401)

    # check user is active
    if user.status != 'active':
        raise ApiError('user not active', 403)

    # assign customer & update last login time
    customer = get_customer(user.email, groups=[user.domain])
    user.update_last_login()

    # generate token
    token = create_token(user.id, user.name, user.email, provider='basic', customer=customer,
                         roles=user.roles, email=user.email, email_verified=user.email_verified)
    return jsonify(token=token.tokenize)