def signup(): if not current_app.config['SIGNUP_ENABLED']: raise ApiError('user signup is disabled', 403) try: user = User.parse(request.json) except Exception as e: raise ApiError(str(e), 400) # set sign-up defaults user.roles = ['user'] user.email_verified = False # check allowed domain if not_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: user.send_confirmation() raise ApiError('email not verified', 403) # check user is active & update last login if user.status != 'active': raise ApiError('user not active', 403) user.update_last_login() # assign customers customers = get_customers(user.email, groups=[user.domain]) auth_audit_trail.send(current_app._get_current_object(), event='basic-auth-signup', message='user signup using BasicAuth', user=user.email, customers=customers, scopes=Permission.lookup(user.email, groups=user.roles), resource_id=user.id, type='user', request=request) # generate token token = create_token(user_id=user.id, name=user.name, login=user.email, provider='basic', customers=customers, roles=user.roles, email=user.email, email_verified=user.email_verified) return jsonify(token=token.tokenize)
def update_user(user_id): if not request.json: raise ApiError('nothing to change', 400) user = User.find_by_id(user_id) if not user: raise ApiError('not found', 404) if request.json.get('email'): user_by_email = User.find_by_email(request.json['email']) if user_by_email and user_by_email.id != user.id: raise ApiError('user with that email already exists', 409) if request.json.get('roles'): want_scopes = Permission.lookup(login='', roles=request.json['roles']) for want_scope in want_scopes: if not Permission.is_in_scope(want_scope, have_scopes=g.scopes): raise ApiError("Requested scope '{}' not in existing scopes: {}".format( want_scope, ','.join(g.scopes)), 403) admin_audit_trail.send(current_app._get_current_object(), event='user-updated', message='', user=g.login, customers=g.customers, scopes=g.scopes, resource_id=user.id, type='user', request=request) if user.update(**request.json): return jsonify(status='ok') else: raise ApiError('failed to update user', 500)
def create_user(): try: user = User.parse(request.json) except Exception as e: raise ApiError(str(e), 400) # check allowed domain if not_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, send confirmation email if current_app.config['EMAIL_VERIFICATION'] and not user.email_verified: user.send_confirmation() admin_audit_trail.send(current_app._get_current_object(), event='user-created', message='', user=g.user, customers=g.customers, scopes=g.scopes, resource_id=user.id, type='user', request=request) if user: return jsonify(status='ok', id=user.id, user=user.serialize), 201 else: raise ApiError('create user failed', 500)
def search_users(): query = qb.from_params(request.args) users = User.find_all(query) # add admins defined in server config if 'admin' in request.args.getlist('roles'): for admin in set(current_app.config['ADMIN_USERS']): user = User.find_by_email(admin) if user: users.append(user) # remove admins whose default role is 'user' if 'admin' not in request.args.getlist('roles'): users = [u for u in users if 'admin' not in u.roles] if users: return jsonify(status='ok', users=[user.serialize for user in users], domains=current_app.config['ALLOWED_EMAIL_DOMAINS'], total=len(users)) else: return jsonify(status='ok', message='not found', users=[], domains=current_app.config['ALLOWED_EMAIL_DOMAINS'], total=0)
def update_me(): if not request.json: raise ApiError('nothing to change', 400) if 'roles' in request.json: raise ApiError('not allowed to update roles', 400) if 'email_verified' in request.json: raise ApiError('not allowed to set email verified', 400) user = User.find_by_id(g.user_id) if not user: raise ApiError('not found', 404) if 'email' in request.json: user_by_email = User.find_by_email(email=request.json['email']) if user_by_email and user_by_email.id != user.id: raise ApiError('user with that email already exists', 409) write_audit_trail.send(current_app._get_current_object(), event='user-me-updated', message='', user=g.login, customers=g.customers, scopes=g.scopes, resource_id=user.id, type='user', request=request) if user.update(**request.json): return jsonify(status='ok') else: raise ApiError('failed to update user', 500)
def signup(): if not current_app.config['SIGNUP_ENABLED']: raise ApiError('user signup is disabled', 403) try: user = User.parse(request.json) except Exception as e: raise ApiError(str(e), 400) # set sign-up defaults user.roles = ['user'] user.email_verified = False # check allowed domain if not_authorized('ALLOWED_EMAIL_DOMAINS', groups=[user.domain]): raise ApiError('unauthorized domain', 403) if User.find_by_username(username=user.email): raise ApiError('user with that email 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: user.send_confirmation() raise ApiError('email not verified', 403) # check user is active & update last login if user.status != 'active': raise ApiError('User {} not active'.format(user.login), 403) user.update_last_login() groups = [g.name for g in user.get_groups()] scopes = Permission.lookup(login=user.login, roles=user.roles + groups) customers = get_customers(login=user.login, groups=[user.domain] + groups) auth_audit_trail.send(current_app._get_current_object(), event='basic-auth-signup', message='user signup using BasicAuth', user=user.login, customers=customers, scopes=scopes, resource_id=user.id, type='user', request=request) # generate token token = create_token(user_id=user.id, name=user.name, login=user.login, provider='basic', customers=customers, scopes=scopes, roles=user.roles, groups=groups, email=user.email, email_verified=user.email_verified) return jsonify(token=token.tokenize)
def create_user(name, login): email = login if '@' in login else None user = User(name=name or login, login=login, password=generate_password_hash(password), roles=current_app.config['ADMIN_ROLES'], text=text, email=email, email_verified=bool(email)) try: user = user.create() except Exception as e: click.echo(f'ERROR: {e}') else: return user
def create_user(): if current_app.config['AUTH_PROVIDER'] != 'basic': raise ApiError( 'must use {} login flow to create new user'.format( current_app.config['AUTH_PROVIDER']), 400) try: user = User.parse(request.json) except Exception as e: raise ApiError(str(e), 400) # check allowed domain if not_authorized('ALLOWED_EMAIL_DOMAINS', groups=[user.domain]): raise ApiError('unauthorized domain', 403) if User.find_by_username(username=user.email): raise ApiError('user with that email already exists', 409) want_scopes = Permission.lookup(login=user.email, roles=user.roles) for want_scope in want_scopes: if not Permission.is_in_scope(want_scope, have_scopes=g.scopes): raise ApiError( "Requested scope '{}' not in existing scopes: {}".format( want_scope, ','.join(g.scopes)), 403) try: user = user.create() except Exception as e: ApiError(str(e), 500) # if email verification is enforced, send confirmation email if current_app.config['EMAIL_VERIFICATION'] and not user.email_verified: user.send_confirmation() admin_audit_trail.send(current_app._get_current_object(), event='user-created', message='', user=g.login, customers=g.customers, scopes=g.scopes, resource_id=user.id, type='user', request=request) if user: return jsonify(status='ok', id=user.id, user=user.serialize), 201 else: raise ApiError('create user failed', 500)
def create_user(admin): user = User( name=admin, email=admin, password=generate_password_hash(password), roles=None, text='Admin user created by alertad script', email_verified=True ) try: db.get_db() # init db on global app context user = user.create() except Exception as e: click.echo('ERROR: {}'.format(e)) else: click.echo('{} {}'.format(user.id, user.name))
def update_user(user_id): if not request.json: raise ApiError("nothing to change", 400) user = User.find_by_id(user_id) if not user: raise ApiError("not found", 404) if 'email' in request.json and User.find_by_email(request.json['email']): raise ApiError("user with email already exists", 409) if user.update(**request.json): return jsonify(status="ok") else: raise ApiError("failed to update user", 500)
def get_me_attributes(): user = User.find_by_id(g.user_id) if user: return jsonify(status='ok', total=1, attributes=user.attributes) else: raise ApiError('not found', 404)
def get_user(user_id): user = User.find_by_id(user_id) if user: return jsonify(status='ok', total=1, user=user.serialize) else: raise ApiError('not found', 404)
def create_user(admin): email = admin if '@' in admin else None user = User(name='Admin user', login=admin, password=generate_password_hash(password), roles=['admin'], text='Created by alertad script', email=email, email_verified=bool(email)) try: db.get_db() # init db on global app context user = user.create() except Exception as e: click.echo('ERROR: {}'.format(e)) else: click.echo('{} {}'.format(user.id, user.name))
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.check_credentials(username, password) if not user: 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: user.send_confirmation() raise ApiError('email not verified', 401) # check allowed domain if not_authorized('ALLOWED_EMAIL_DOMAINS', groups=[user.domain]): raise ApiError('unauthorized domain', 403) # assign customers customers = get_customers(user.email, groups=[user.domain]) # generate token token = create_token(user.id, user.name, user.email, provider='basic', customers=customers, roles=user.roles, email=user.email, email_verified=user.email_verified) return jsonify(token=token.tokenize)
def update_me_attributes(): if not request.json.get('attributes', None): raise ApiError("must supply 'attributes' as json data", 400) user = User.find_by_id(g.user_id) if not user: raise ApiError('not found', 404) resp = user.update_attributes(request.json['attributes']) write_audit_trail.send(current_app._get_current_object(), event='user-me-attributes-updated', message='', user=g.login, customers=g.customers, scopes=g.scopes, resource_id=user.id, type='user', request=request) if resp: return jsonify(status='ok') else: raise ApiError('failed to update attributes', 500)
def update_user(user_id): if not request.json: raise ApiError("nothing to change", 400) user = User.get(user_id) if not user: raise ApiError("not found", 404) if 'email' in request.json and User.get_by_email(request.json['email']): raise ApiError("user with email already exists", 409) if user.update(**request.json): return jsonify(status="ok") else: raise ApiError("failed to update user", 500)
def signup(): try: user = User.parse(request.json) except Exception as e: raise ApiError(str(e), 400) # set sign-up defaults user.roles = ['user'] user.email_verified = False # 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 customers & update last login time customers = get_customers(user.email, groups=[user.domain]) user.update_last_login() # generate token token = create_token(user.id, user.name, user.email, provider='basic', customers=customers, roles=user.roles, email=user.email, email_verified=user.email_verified) return jsonify(token=token.tokenize)
def verify_email(hash): user = User.verify_hash(hash) if user and not user.email_verified: user.set_email_verified() return render_template('auth/verify_success.html', email=user.email) else: return render_template('auth/verify_failed.html')
def create_user(admin): email = admin if '@' in admin else None user = User( name='Admin user', login=admin, password=generate_password_hash(password), roles=['admin'], text='Created by alertad script', email=email, email_verified=bool(email) ) try: db.get_db() # init db on global app context user = user.create() except Exception as e: click.echo('ERROR: {}'.format(e)) else: click.echo('{} {}'.format(user.id, user.name))
def delete_user(user_id): user = User.find_by_id(user_id) if not user: raise ApiError("not found", 404) if user.delete(): return jsonify(status="ok") else: raise ApiError("failed to delete user", 500)
def delete_user(user_id): user = User.find_by_id(user_id) if not user: raise ApiError('not found', 404) if user.delete(): return jsonify(status='ok') else: raise ApiError('failed to delete user', 500)
def verify_email(hash): user = User.verify_hash(hash, salt='confirm') if user: if user.email_verified: raise ApiError('email already verified', 400) user.set_email_verified() return jsonify(status='ok', message='email address {} confirmed'.format(user.email)) else: raise ApiError('invalid confirmation hash', 400)
def users(): """List admin users.""" for admin in current_app.config['ADMIN_USERS']: try: db.get_db() # init db on global app context user = User.find_by_username(admin) except Exception as e: click.echo('ERROR: {}'.format(e)) else: if user: click.echo('{} {}'.format(user.id, user.name))
def login(): # Retrieve required fields from client request try: email = request.json.get('username', None) or request.json['email'] password = request.json['password'] except KeyError: raise ApiError("must supply 'username' and 'password'", 401) username = email.split("@")[0] domain = email.split("@")[1] # Validate LDAP domain if domain not in current_app.config["LDAP_DOMAINS"]: raise ApiError("unauthorized domain", 403) userdn = current_app.config["LDAP_DOMAINS"][domain] % username # Attempt LDAP AUTH try: trace_level = 2 if current_app.debug else 0 ldap_connection = ldap.initialize(current_app.config['LDAP_URL'], trace_level=trace_level) ldap_connection.simple_bind_s(userdn, password) except ldap.INVALID_CREDENTIALS: raise ApiError("invalid username or password", 401) except Exception as e: raise ApiError(str(e), 500) # Create user if not yet there user = User.find_by_email(email=email) if not user: user = User(username, email, "", ["user"], "LDAP user", email_verified=True) user.create() # Check user is active if user.status != 'active': raise ApiError('user not active', 403) # Assign customers & update last login time customers = get_customers(user.email, groups=[user.domain]) user.update_last_login() # Generate token token = create_token(user.id, user.name, user.email, provider='basic_ldap', customers=customers, roles=user.roles, email=user.email, email_verified=user.email_verified) return jsonify(token=token.tokenize)
def update_user_attributes(user_id): if not request.json.get('attributes', None): raise ApiError("must supply 'attributes' as json data", 400) user = User.find_by_id(user_id) if not user: raise ApiError("not found", 404) if user.update_attributes(request.json['attributes']): return jsonify(status="ok") else: raise ApiError("failed to update attributes", 500)
def delete_user(user_id): user = User.find_by_id(user_id) if not user: raise ApiError('not found', 404) admin_audit_trail.send(current_app._get_current_object(), event='user-deleted', message='', user=g.login, customers=g.customers, scopes=g.scopes, resource_id=user.id, type='user', request=request) if user.delete(): return jsonify(status='ok') else: raise ApiError('failed to delete user', 500)
def create_user(): if current_app.config['AUTH_PROVIDER'] != 'basic': raise ApiError( 'must use {} login flow to create new user'.format(current_app.config['AUTH_PROVIDER']), 400) try: user = User.parse(request.json) except Exception as e: raise ApiError(str(e), 400) # check allowed domain if not_authorized('ALLOWED_EMAIL_DOMAINS', groups=[user.domain]): raise ApiError('unauthorized domain', 403) if User.find_by_username(username=user.email): raise ApiError('user with that email already exists', 409) want_scopes = Permission.lookup(login=user.email, roles=user.roles) for want_scope in want_scopes: if not Permission.is_in_scope(want_scope, have_scopes=g.scopes): raise ApiError("Requested scope '{}' not in existing scopes: {}".format( want_scope, ','.join(g.scopes)), 403) try: user = user.create() except Exception as e: ApiError(str(e), 500) # if email verification is enforced, send confirmation email if current_app.config['EMAIL_VERIFICATION'] and not user.email_verified: user.send_confirmation() admin_audit_trail.send(current_app._get_current_object(), event='user-created', message='', user=g.login, customers=g.customers, scopes=g.scopes, resource_id=user.id, type='user', request=request) if user: return jsonify(status='ok', id=user.id, user=user.serialize), 201 else: raise ApiError('create user failed', 500)
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)
def verify_email(hash): user = User.verify_hash(hash, salt='confirm') if user: if user.email_verified: raise ApiError('email already verified', 400) user.set_email_verified() auth_audit_trail.send(current_app._get_current_object(), event='basic-auth-verify-email', message='user confirm email address', user=user.email, customers=[], scopes=[], resource_id=user.id, type='user', request=request) return jsonify(status='ok', message='email address {} confirmed'.format(user.email)) else: raise ApiError('invalid confirmation hash', 400)
def update_me_attributes(): if not request.json.get('attributes', None): raise ApiError("must supply 'attributes' as json data", 400) user = User.find_by_id(g.user_id) if not user: raise ApiError('not found', 404) write_audit_trail.send(current_app._get_current_object(), event='user-me-attributes-updated', message='', user=g.login, customers=g.customers, scopes=g.scopes, resource_id=user.id, type='user', request=request) if user.update_attributes(request.json['attributes']): return jsonify(status='ok') else: raise ApiError('failed to update attributes', 500)
def reset(hash): try: password = request.json['password'] except KeyError: raise ApiError("must supply 'password'", 400) user = User.verify_hash(hash, salt='reset') if user: if not user.is_active: raise ApiError('user not active', 403) user.reset_password(password) auth_audit_trail.send(current_app._get_current_object(), event='basic-auth-password-reset', message='user password reset successful', user=user.email, customers=[], scopes=[], resource_id=user.id, type='user', request=request) return jsonify(status='ok', message='password reset successful') else: raise ApiError('invalid password reset hash', 400)
def list_users(): query = qb.from_params(request.args) users = User.find_all(query) if users: return jsonify( status='ok', users=[user.serialize for user in users], domains=current_app.config['ALLOWED_EMAIL_DOMAINS'], total=len(users) ) else: return jsonify( status='ok', message='not found', users=[], domains=current_app.config['ALLOWED_EMAIL_DOMAINS'], total=0 )
def forgot(): try: email = request.json['email'] except KeyError: raise ApiError("must supply 'email'", 400) user = User.find_by_email(email) if user: if not user.is_active: raise ApiError('user not active', 403) user.send_password_reset() auth_audit_trail.send(current_app._get_current_object(), event='basic-auth-password-forgot', message='user requested password reset', user=user.email, customers=[], scopes=[], resource_id=user.id, type='user', request=request) return jsonify(status='ok', message='password reset sent') else: raise ApiError('invalid email address', 400)
def get_user_groups(user_id): user = User.find_by_id(user_id) if not user: raise ApiError('not found', 404) user_groups = user.get_groups() if user_groups: return jsonify( status='ok', groups=[group.serialize for group in user_groups], total=len(user_groups) ) else: return jsonify( status='ok', message='not found', groups=[], total=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.check_credentials(username, password) if not user: 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: user.send_confirmation() raise ApiError('email not verified', 403) # check allowed domain if not_authorized('ALLOWED_EMAIL_DOMAINS', groups=[user.domain]): raise ApiError('unauthorized domain', 403) # check user is active & update last login if user.status != 'active': raise ApiError('User {} not active'.format(user.login), 403) user.update_last_login() groups = [g.name for g in user.get_groups()] scopes = Permission.lookup(login=user.login, roles=user.roles + groups) customers = get_customers(login=user.login, groups=[user.domain] + groups) auth_audit_trail.send(current_app._get_current_object(), event='basic-auth-login', message='user login via BasicAuth', user=user.login, customers=customers, scopes=scopes, resource_id=user.id, type='user', request=request) # generate token token = create_token(user_id=user.id, name=user.name, login=user.login, provider='basic', customers=customers, scopes=scopes, roles=user.roles, groups=groups, email=user.email, email_verified=user.email_verified) return jsonify(token=token.tokenize)
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)
def login(): # Retrieve required fields from client request try: email = request.json.get('username', None) or request.json['email'] password = request.json['password'] except KeyError: raise ApiError("must supply 'username' and 'password'", 401) username, domain = email.split('@') # Validate LDAP domain if domain not in current_app.config['LDAP_DOMAINS']: raise ApiError('unauthorized domain', 403) userdn = current_app.config['LDAP_DOMAINS'][domain] % username # Attempt LDAP AUTH try: trace_level = 2 if current_app.debug else 0 ldap_connection = ldap.initialize(current_app.config['LDAP_URL'], trace_level=trace_level) ldap_connection.simple_bind_s(userdn, password) except ldap.INVALID_CREDENTIALS: raise ApiError('invalid username or password', 401) except Exception as e: raise ApiError(str(e), 500) # Create user if not yet there user = User.find_by_username(username=email) if not user: user = User(name=username, login=email, password='', email=email, roles=[], text='LDAP user', email_verified=True) try: user = user.create() except Exception as e: ApiError(str(e), 500) # Assign customers & update last login time groups = list() try: groups_filters = current_app.config.get('LDAP_DOMAINS_GROUP', {}) base_dns = current_app.config.get('LDAP_DOMAINS_BASEDN', {}) if domain in groups_filters and domain in base_dns: resultID = ldap_connection.search( base_dns[domain], ldap.SCOPE_SUBTREE, groups_filters[domain].format(username=username, email=email, userdn=userdn), ['cn'] ) resultTypes, results = ldap_connection.result(resultID) for _dn, attributes in results: groups.append(attributes['cn'][0].decode('utf-8')) except ldap.LDAPError as e: raise ApiError(str(e), 500) # Check user is active if user.status != 'active': raise ApiError('User {} not active'.format(email), 403) user.update_last_login() scopes = Permission.lookup(login=user.email, roles=user.roles) customers = get_customers(login=user.email, groups=[user.domain] + groups) auth_audit_trail.send(current_app._get_current_object(), event='basic-ldap-login', message='user login via LDAP', user=user.email, customers=customers, scopes=scopes, resource_id=user.id, type='user', request=request) # Generate token token = create_token(user_id=user.id, name=user.name, login=user.email, provider='ldap', customers=customers, scopes=scopes, roles=user.roles, email=user.email, email_verified=user.email_verified) return jsonify(token=token.tokenize)
def wrapped(*args, **kwargs): # API Key (Authorization: Key <key>) if 'Authorization' in request.headers: auth_header = request.headers['Authorization'] m = re.match(r'Key (\S+)', auth_header) key = m.group(1) if m else None # API Key (X-API-Key: <key>) elif 'X-API-Key' in request.headers: key = request.headers['X-API-Key'] # API Key (/foo?api-key=<key>) else: key = request.args.get('api-key', None) if key: key_info = ApiKey.verify_key(key) if not key_info: raise ApiError("API key parameter '%s' is invalid" % key, 401) g.user_id = None g.login = key_info.user g.customers = [key_info.customer] if key_info.customer else [] g.scopes = key_info.scopes # type: List[Scope] if not Permission.is_in_scope(scope, have_scopes=g.scopes): raise ApiError('Missing required scope: %s' % scope.value, 403) else: return f(*args, **kwargs) # Bearer Token auth_header = request.headers.get('Authorization', '') m = re.match(r'Bearer (\S+)', auth_header) token = m.group(1) if m else None if token: try: jwt = Jwt.parse(token) except DecodeError: raise ApiError('Token is invalid', 401) except ExpiredSignature: raise ApiError('Token has expired', 401) except InvalidAudience: raise ApiError('Invalid audience', 401) g.user_id = jwt.subject g.login = jwt.preferred_username g.customers = jwt.customers g.scopes = jwt.scopes # type: List[Scope] if not Permission.is_in_scope(scope, have_scopes=g.scopes): raise ApiError('Missing required scope: %s' % scope.value, 403) else: return f(*args, **kwargs) # Basic Auth auth_header = request.headers.get('Authorization', '') m = re.match(r'Basic (\S+)', auth_header) credentials = m.group(1) if m else None if credentials: try: username, password = base64.b64decode(credentials).decode('utf-8').split(':') except Exception as e: raise BasicAuthError('Invalid credentials', 400, errors=[str(e)]) user = User.check_credentials(username, password) if not user: raise BasicAuthError('Authorization required', 401) if current_app.config['EMAIL_VERIFICATION'] and not user.email_verified: raise BasicAuthError('email not verified', 401) if not_authorized('ALLOWED_EMAIL_DOMAINS', groups=[user.domain]): raise BasicAuthError('Unauthorized domain', 403) g.user_id = user.id g.login = user.email g.customers = get_customers(user.email, groups=[user.domain]) g.scopes = Permission.lookup(user.email, roles=user.roles) # type: List[Scope] if not Permission.is_in_scope(scope, have_scopes=g.scopes): raise BasicAuthError('Missing required scope: %s' % scope.value, 403) else: return f(*args, **kwargs) if not current_app.config['AUTH_REQUIRED']: g.user_id = None g.login = None g.customers = [] g.scopes = [] # type: List[Scope] return f(*args, **kwargs) # Google App Engine Cron Service if request.headers.get('X-Appengine-Cron', False) and request.headers.get('X-Forwarded-For', '') == '0.1.0.1': return f(*args, **kwargs) raise ApiError('Missing authorization API Key or Bearer Token', 401)
def openid(): oidc_configuration, jwt_key_set = get_oidc_configuration(current_app) token_endpoint = oidc_configuration['token_endpoint'] userinfo_endpoint = oidc_configuration['userinfo_endpoint'] data = { 'grant_type': 'authorization_code', 'code': request.json['code'], 'redirect_uri': request.json['redirectUri'], 'client_id': request.json['clientId'], 'client_secret': current_app.config['OAUTH2_CLIENT_SECRET'], } r = requests.post(token_endpoint, data) token = r.json() try: if current_app.config['OIDC_VERIFY_TOKEN']: jwt_header = jwt.get_unverified_header(token['id_token']) public_key = jwt_key_set[jwt_header['kid']] id_token = jwt.decode( token['id_token'], key=public_key, algorithms=jwt_header['alg'] ) else: id_token = jwt.decode( token['id_token'], verify=False ) except Exception: current_app.logger.warning('No ID token in OpenID Connect token response.') id_token = {} try: headers = {'Authorization': '{} {}'.format(token.get('token_type', 'Bearer'), token['access_token'])} r = requests.get(userinfo_endpoint, headers=headers) userinfo = r.json() except Exception: raise ApiError('No access token in OpenID Connect token response.') subject = userinfo['sub'] name = userinfo.get('name') or id_token.get('name') nickname = userinfo.get('nickname') email = userinfo.get('email') or id_token.get('email') email_verified = userinfo.get('email_verified', id_token.get('email_verified', bool(email))) picture = userinfo.get('picture') or id_token.get('picture') role_claim = current_app.config['OIDC_ROLE_CLAIM'] group_claim = current_app.config['OIDC_GROUP_CLAIM'] custom_claims = { role_claim: userinfo.get(role_claim) or id_token.get(role_claim, []), group_claim: userinfo.get(group_claim) or id_token.get(group_claim, []), } login = userinfo.get('preferred_username', nickname or email) if not login: raise ApiError("Must support one of the following OpenID claims: 'preferred_username', 'nickname' or 'email'", 400) user = User.find_by_id(id=subject) if not user: user = User(id=subject, name=name, login=login, password='', email=email, roles=[], text='', email_verified=email_verified) user.create() else: user.update(login=login, email=email) roles = custom_claims[role_claim] or user.roles groups = custom_claims[group_claim] if user.status != 'active': raise ApiError('User {} is not active'.format(login), 403) if not_authorized('ALLOWED_OIDC_ROLES', roles) and not_authorized('ALLOWED_EMAIL_DOMAINS', groups=[user.domain]): raise ApiError('User {} is not authorized'.format(login), 403) user.update_last_login() scopes = Permission.lookup(login, roles) customers = get_customers(login, groups=[user.domain] + groups) auth_audit_trail.send(current_app._get_current_object(), event='openid-login', message='user login via OpenID Connect', user=login, customers=customers, scopes=scopes, resource_id=subject, type='user', request=request) token = create_token(user_id=subject, name=name, login=login, provider='openid', customers=customers, scopes=scopes, email=email, email_verified=email_verified, picture=picture, **custom_claims) return jsonify(token=token.tokenize)