def post(self): access_token_url = "https://accounts.google.com/o/oauth2/token" people_api_url = "https://www.googleapis.com/plus/v1/people/me/openIdConnect" self.reqparse.add_argument("clientId", type=str, required=True, location="json") self.reqparse.add_argument("redirectUri", type=str, required=True, location="json") self.reqparse.add_argument("code", type=str, required=True, location="json") args = self.reqparse.parse_args() # Step 1. Exchange authorization code for access token payload = { "client_id": args["clientId"], "grant_type": "authorization_code", "redirect_uri": args["redirectUri"], "code": args["code"], "client_secret": current_app.config.get("GOOGLE_SECRET"), } r = requests.post(access_token_url, data=payload) token = r.json() # Step 2. Retrieve information about the current user headers = {"Authorization": "Bearer {0}".format(token["access_token"])} r = requests.get(people_api_url, headers=headers) profile = r.json() user = user_service.get_by_email(profile["email"]) if user: metrics.send("successful_login", "counter", 1) return dict(token=create_token(user))
def _update_user(self, roles): """ create or update a local user instance. """ # try to get user from local database user = user_service.get_by_email(self.ldap_principal) # create them a local account if not user: user = user_service.create( self.ldap_username, get_psuedo_random_string(), self.ldap_principal, True, '', # thumbnailPhotoUrl list(roles) ) else: # we add 'lemur' specific roles, so they do not get marked as removed for ur in user.roles: if ur.authority_id: roles.add(ur) # update any changes to the user user_service.update( user.id, self.ldap_username, self.ldap_principal, user.active, user.profile_picture, list(roles) ) return user
def import_certificate(**kwargs): """ Uploads already minted certificates and pulls the required information into Lemur. This is to be used for certificates that are created outside of Lemur but should still be tracked. Internally this is used to bootstrap Lemur with external certificates, and used when certificates are 'discovered' through various discovery techniques. was still in aws. :param kwargs: """ from lemur.users import service as user_service from lemur.notifications import service as notification_service cert = Certificate(kwargs['public_certificate'], chain=kwargs['intermediate_certificate']) # TODO future source plugins might have a better understanding of who the 'owner' is we should support this cert.owner = kwargs.get('owner', current_app.config.get('LEMUR_SECURITY_TEAM_EMAIL')[0]) cert.creator = kwargs.get('creator', user_service.get_by_email('lemur@nobody')) # NOTE existing certs may not follow our naming standard we will # overwrite the generated name with the actual cert name if kwargs.get('name'): cert.name = kwargs.get('name') if kwargs.get('user'): cert.user = kwargs.get('user') notification_name = 'DEFAULT_SECURITY' notifications = notification_service.create_default_expiration_notifications(notification_name, current_app.config.get('LEMUR_SECURITY_TEAM_EMAIL')) cert.notifications = notifications cert = database.create(cert) return cert
def post(self): access_token_url = 'https://accounts.google.com/o/oauth2/token' people_api_url = 'https://www.googleapis.com/plus/v1/people/me/openIdConnect' self.reqparse.add_argument('clientId', type=str, required=True, location='json') self.reqparse.add_argument('redirectUri', type=str, required=True, location='json') self.reqparse.add_argument('code', type=str, required=True, location='json') args = self.reqparse.parse_args() # Step 1. Exchange authorization code for access token payload = { 'client_id': args['clientId'], 'grant_type': 'authorization_code', 'redirect_uri': args['redirectUri'], 'code': args['code'], 'client_secret': current_app.config.get('GOOGLE_SECRET') } r = requests.post(access_token_url, data=payload) token = r.json() # Step 2. Retrieve information about the current user headers = {'Authorization': 'Bearer {0}'.format(token['access_token'])} r = requests.get(people_api_url, headers=headers) profile = r.json() user = user_service.get_by_email(profile['email']) if user: return dict(token=create_token(user))
def post(self): """ .. http:post:: /auth/login Login with username:password **Example request**: .. sourcecode:: http POST /auth/login HTTP/1.1 Host: example.com Accept: application/json, text/javascript { "username": "******", "password": "******" } **Example response**: .. sourcecode:: http HTTP/1.1 200 OK Vary: Accept Content-Type: text/javascript { "token": "12343243243" } :arg username: username :arg password: password :statuscode 401: invalid credentials :statuscode 200: no error """ self.reqparse.add_argument('username', type=str, required=True, location='json') self.reqparse.add_argument('password', type=str, required=True, location='json') args = self.reqparse.parse_args() if '@' in args['username']: user = user_service.get_by_email(args['username']) else: user = user_service.get_by_username(args['username']) if user and user.check_password(args['password']): # Tell Flask-Principal the identity changed identity_changed.send(current_app._get_current_object(), identity=Identity(user.id)) metrics.send('successful_login', 'counter', 1) return dict(token=create_token(user)) metrics.send('invalid_login', 'counter', 1) return dict(message='The supplied credentials are invalid'), 401
def post(self): access_token_url = 'https://accounts.google.com/o/oauth2/token' people_api_url = 'https://www.googleapis.com/plus/v1/people/me/openIdConnect' self.reqparse.add_argument('clientId', type=str, required=True, location='json') self.reqparse.add_argument('redirectUri', type=str, required=True, location='json') self.reqparse.add_argument('code', type=str, required=True, location='json') args = self.reqparse.parse_args() # Step 1. Exchange authorization code for access token payload = { 'client_id': args['clientId'], 'grant_type': 'authorization_code', 'redirect_uri': args['redirectUri'], 'code': args['code'], 'client_secret': current_app.config.get('GOOGLE_SECRET') } r = requests.post(access_token_url, data=payload) token = r.json() # Step 2. Retrieve information about the current user headers = {'Authorization': 'Bearer {0}'.format(token['access_token'])} r = requests.get(people_api_url, headers=headers) profile = r.json() user = user_service.get_by_email(profile['email']) if not user.active: metrics.send('invalid_login', 'counter', 1) return dict(message='The supplied credentials are invalid.'), 403 if user: metrics.send('successful_login', 'counter', 1) return dict(token=create_token(user)) metrics.send('invalid_login', 'counter', 1)
def create_certificate(pending_certificate, certificate, user): """ Create and store a certificate with pending certificate's info :arg pending_certificate: PendingCertificate which will populate the certificate :arg certificate: dict from Authority, which contains the body, chain and external id :arg user: User that called this function, used as 'creator' of the certificate if it does not have an owner """ certificate["owner"] = pending_certificate.owner data, errors = CertificateUploadInputSchema().load(certificate) if errors: raise Exception( "Unable to create certificate: {reasons}".format(reasons=errors)) data.update(vars(pending_certificate)) # Copy relationships, vars doesn't copy this without explicit fields data["notifications"] = list(pending_certificate.notifications) data["destinations"] = list(pending_certificate.destinations) data["sources"] = list(pending_certificate.sources) data["roles"] = list(pending_certificate.roles) data["replaces"] = list(pending_certificate.replaces) data["rotation_policy"] = pending_certificate.rotation_policy # Replace external id and chain with the one fetched from source data["external_id"] = certificate["external_id"] data["chain"] = certificate["chain"] creator = user_service.get_by_email(pending_certificate.owner) if not creator: # Owner of the pending certificate is not the creator, so use the current user who called # this as the creator (usually lemur) creator = user if pending_certificate.rename: # If generating name from certificate, remove the one from pending certificate del data["name"] data["creator"] = creator cert = certificate_service.import_certificate(**data) database.update(cert) metrics.send("certificate_issued", "counter", 1, metric_tags=dict(owner=cert.owner, issuer=cert.issuer)) log_service.audit_log( "certificate_from_pending_certificate", cert.name, f"Created from the pending certificate {pending_certificate.name}") return cert
def retrieve_user(user_api_url, access_token): """ Fetch user information from provided user api_url. :param user_api_url: :param access_token: :return: """ user_params = dict(access_token=access_token, schema='profile') # retrieve information about the current user. r = requests.get(user_api_url, params=user_params) profile = r.json() user = user_service.get_by_email(profile['email']) return user, profile
def post(self): access_token_url = "https://accounts.google.com/o/oauth2/token" people_api_url = "https://www.googleapis.com/plus/v1/people/me/openIdConnect" self.reqparse.add_argument("clientId", type=str, required=True, location="json") self.reqparse.add_argument( "redirectUri", type=str, required=True, location="json" ) self.reqparse.add_argument("code", type=str, required=True, location="json") args = self.reqparse.parse_args() # Step 1. Exchange authorization code for access token payload = { "client_id": args["clientId"], "grant_type": "authorization_code", "redirect_uri": args["redirectUri"], "code": args["code"], "client_secret": current_app.config.get("GOOGLE_SECRET"), } r = requests.post(access_token_url, data=payload) token = r.json() # Step 2. Retrieve information about the current user headers = {"Authorization": "Bearer {0}".format(token["access_token"])} r = requests.get(people_api_url, headers=headers) profile = r.json() user = user_service.get_by_email(profile["email"]) if not (user and user.active): metrics.send( "login", "counter", 1, metric_tags={"status": FAILURE_METRIC_STATUS} ) return dict(message="The supplied credentials are invalid."), 403 if user: metrics.send( "login", "counter", 1, metric_tags={"status": SUCCESS_METRIC_STATUS} ) return dict(token=create_token(user)) metrics.send( "login", "counter", 1, metric_tags={"status": FAILURE_METRIC_STATUS} )
def import_certificate(**kwargs): """ Uploads already minted certificates and pulls the required information into Lemur. This is to be used for certificates that are created outside of Lemur but should still be tracked. Internally this is used to bootstrap Lemur with external certificates, and used when certificates are 'discovered' through various discovery techniques. was still in aws. :param kwargs: """ from lemur.users import service as user_service from lemur.notifications import service as notification_service cert = Certificate(kwargs['public_certificate'], chain=kwargs['intermediate_certificate']) # TODO future source plugins might have a better understanding of who the 'owner' is we should support this cert.owner = kwargs.get( 'owner', current_app.config.get('LEMUR_SECURITY_TEAM_EMAIL')[0]) cert.creator = kwargs.get('creator', user_service.get_by_email('lemur@nobody')) # NOTE existing certs may not follow our naming standard we will # overwrite the generated name with the actual cert name if kwargs.get('name'): cert.name = kwargs.get('name') if kwargs.get('user'): cert.user = kwargs.get('user') notification_name = 'DEFAULT_SECURITY' notifications = notification_service.create_default_expiration_notifications( notification_name, current_app.config.get('LEMUR_SECURITY_TEAM_EMAIL')) if kwargs.get('replacements'): database.update_list(cert, 'replaces', Certificate, kwargs['replacements']) cert.notifications = notifications cert = database.create(cert) return cert
def create_certificate(pending_certificate, certificate, user): """ Create and store a certificate with pending certificate's info Args: pending_certificate: PendingCertificate which will populate the certificate certificate: dict from Authority, which contains the body, chain and external id user: User that called this function, used as 'creator' of the certificate if it does not have an owner """ certificate['owner'] = pending_certificate.owner data, errors = CertificateUploadInputSchema().load(certificate) if errors: raise Exception( "Unable to create certificate: {reasons}".format(reasons=errors)) data.update(vars(pending_certificate)) # Copy relationships, vars doesn't copy this without explicit fields data['notifications'] = list(pending_certificate.notifications) data['destinations'] = list(pending_certificate.destinations) data['sources'] = list(pending_certificate.sources) data['roles'] = list(pending_certificate.roles) data['replaces'] = list(pending_certificate.replaces) data['rotation_policy'] = pending_certificate.rotation_policy # Replace external id and chain with the one fetched from source data['external_id'] = certificate['external_id'] data['chain'] = certificate['chain'] creator = user_service.get_by_email(pending_certificate.owner) if not creator: # Owner of the pending certificate is not the creator, so use the current user who called # this as the creator (usually lemur) creator = user if pending_certificate.rename: # If generating name from certificate, remove the one from pending certificate del data['name'] data['creator'] = creator cert = certificate_service.import_certificate(**data) database.update(cert) return cert
def retrieve_user(user_api_url, access_token): """ Fetch user information from provided user api_url. :param user_api_url: :param access_token: :return: """ user_params = dict(access_token=access_token, schema="profile") headers = {} if current_app.config.get("PING_INCLUDE_BEARER_TOKEN"): headers = {"Authorization": f"Bearer {access_token}"} # retrieve information about the current user. r = requests.get(user_api_url, params=user_params, headers=headers) profile = r.json() user = user_service.get_by_email(profile["email"]) return user, profile
def create_certificate(pending_certificate, certificate, user): """ Create and store a certificate with pending certificate's info Args: pending_certificate: PendingCertificate which will populate the certificate certificate: dict from Authority, which contains the body, chain and external id user: User that called this function, used as 'creator' of the certificate if it does not have an owner """ certificate['owner'] = pending_certificate.owner data, errors = CertificateUploadInputSchema().load(certificate) if errors: raise Exception("Unable to create certificate: {reasons}".format(reasons=errors)) data.update(vars(pending_certificate)) # Copy relationships, vars doesn't copy this without explicit fields data['notifications'] = list(pending_certificate.notifications) data['destinations'] = list(pending_certificate.destinations) data['sources'] = list(pending_certificate.sources) data['roles'] = list(pending_certificate.roles) data['replaces'] = list(pending_certificate.replaces) data['rotation_policy'] = pending_certificate.rotation_policy # Replace external id and chain with the one fetched from source data['external_id'] = certificate['external_id'] data['chain'] = certificate['chain'] creator = user_service.get_by_email(pending_certificate.owner) if not creator: # Owner of the pending certificate is not the creator, so use the current user who called # this as the creator (usually lemur) creator = user if pending_certificate.rename: # If generating name from certificate, remove the one from pending certificate del data['name'] data['creator'] = creator cert = certificate_service.import_certificate(**data) database.update(cert) return cert
def post(self): access_token_url = 'https://accounts.google.com/o/oauth2/token' people_api_url = 'https://www.googleapis.com/plus/v1/people/me/openIdConnect' self.reqparse.add_argument('clientId', type=str, required=True, location='json') self.reqparse.add_argument('redirectUri', type=str, required=True, location='json') self.reqparse.add_argument('code', type=str, required=True, location='json') args = self.reqparse.parse_args() # Step 1. Exchange authorization code for access token payload = { 'client_id': args['clientId'], 'grant_type': 'authorization_code', 'redirect_uri': args['redirectUri'], 'code': args['code'], 'client_secret': current_app.config.get('GOOGLE_SECRET') } r = requests.post(access_token_url, data=payload) token = r.json() # Step 2. Retrieve information about the current user headers = {'Authorization': 'Bearer {0}'.format(token['access_token'])} r = requests.get(people_api_url, headers=headers) profile = r.json() user = user_service.get_by_email(profile['email']) if not (user and user.active): metrics.send('login', 'counter', 1, metric_tags={'status': FAILURE_METRIC_STATUS}) return dict(message='The supplied credentials are invalid.'), 403 if user: metrics.send('login', 'counter', 1, metric_tags={'status': SUCCESS_METRIC_STATUS}) return dict(token=create_token(user)) metrics.send('login', 'counter', 1, metric_tags={'status': FAILURE_METRIC_STATUS})
def import_certificate(**kwargs): """ Uploads already minted certificates and pulls the required information into Lemur. This is to be used for certificates that are created outside of Lemur but should still be tracked. Internally this is used to bootstrap Lemur with external certificates, and used when certificates are 'discovered' through various discovery techniques. was still in aws. :param kwargs: """ from lemur.users import service as user_service if not kwargs.get('owner'): kwargs['owner'] = current_app.config.get('LEMUR_SECURITY_TEAM_EMAIL')[0] if not kwargs.get('creator'): kwargs['creator'] = user_service.get_by_email('lemur@nobody') return upload(**kwargs)
def upload(**kwargs): """ Allows for pre-made certificates to be imported into Lemur. """ from lemur.users import service as user_service roles = create_certificate_roles(**kwargs) if kwargs.get('roles'): kwargs['roles'] += roles else: kwargs['roles'] = roles cert = Certificate(**kwargs) cert = database.create(cert) try: g.user.certificates.append(cert) except AttributeError: user = user_service.get_by_email('lemur@nobody') user.certificates.append(cert) return database.update(cert)
def import_certificate(**kwargs): """ Uploads already minted certificates and pulls the required information into Lemur. This is to be used for certificates that are created outside of Lemur but should still be tracked. Internally this is used to bootstrap Lemur with external certificates, and used when certificates are 'discovered' through various discovery techniques. was still in aws. :param kwargs: """ from lemur.users import service as user_service if not kwargs.get('owner'): kwargs['owner'] = current_app.config.get( 'LEMUR_SECURITY_TEAM_EMAIL')[0] if not kwargs.get('creator'): kwargs['creator'] = user_service.get_by_email('lemur@nobody') return upload(**kwargs)
def post(self): self.reqparse.add_argument('clientId', type=str, required=True, location='json') self.reqparse.add_argument('redirectUri', type=str, required=True, location='json') self.reqparse.add_argument('code', type=str, required=True, location='json') args = self.reqparse.parse_args() # take the information we have received from the provider to create a new request params = { 'client_id': args['clientId'], 'grant_type': 'authorization_code', 'scope': 'openid email profile address', 'redirect_uri': args['redirectUri'], 'code': args['code'] } # you can either discover these dynamically or simply configure them access_token_url = current_app.config.get('PING_ACCESS_TOKEN_URL') user_api_url = current_app.config.get('PING_USER_API_URL') # the secret and cliendId will be given to you when you signup for the provider basic = base64.b64encode('{0}:{1}'.format( args['clientId'], current_app.config.get("PING_SECRET"))) headers = {'Authorization': 'Basic {0}'.format(basic)} # exchange authorization code for access token. r = requests.post(access_token_url, headers=headers, params=params) id_token = r.json()['id_token'] access_token = r.json()['access_token'] # fetch token public key header_data = fetch_token_header(id_token) jwks_url = current_app.config.get('PING_JWKS_URL') # retrieve the key material as specified by the token header r = requests.get(jwks_url) for key in r.json()['keys']: if key['kid'] == header_data['kid']: secret = get_rsa_public_key(key['n'], key['e']) algo = header_data['alg'] break else: return dict(message='Key not found'), 403 # validate your token based on the key it was signed with try: jwt.decode(id_token, secret, algorithms=[algo], audience=args['clientId']) except jwt.DecodeError: return dict(message='Token is invalid'), 403 except jwt.ExpiredSignatureError: return dict(message='Token has expired'), 403 except jwt.InvalidTokenError: return dict(message='Token is invalid'), 403 user_params = dict(access_token=access_token, schema='profile') # retrieve information about the current user. r = requests.get(user_api_url, params=user_params) profile = r.json() user = user_service.get_by_email(profile['email']) # update their google 'roles' roles = [] for group in profile['googleGroups']: role = role_service.get_by_name(group) if not role: role = role_service.create( group, description= 'This is a google group based role created by Lemur') roles.append(role) # if we get an sso user create them an account # we still pick a random password in case sso is down if not user: # every user is an operator (tied to a default role) if current_app.config.get('LEMUR_DEFAULT_ROLE'): v = role_service.get_by_name( current_app.config.get('LEMUR_DEFAULT_ROLE')) if v: roles.append(v) user = user_service.create(profile['email'], get_psuedo_random_string(), profile['email'], True, profile.get('thumbnailPhotoUrl'), roles) else: # we add 'lemur' specific roles, so they do not get marked as removed for ur in user.roles: if ur.authority_id: roles.append(ur) # update any changes to the user user_service.update( user.id, profile['email'], profile['email'], True, profile.get('thumbnailPhotoUrl' ), # incase profile isn't google+ enabled roles) # Tell Flask-Principal the identity changed identity_changed.send(current_app._get_current_object(), identity=Identity(user.id)) return dict(token=create_token(user))
def post(self): """ .. http:post:: /auth/login Login with username:password **Example request**: .. sourcecode:: http POST /auth/login HTTP/1.1 Host: example.com Accept: application/json, text/javascript { "username": "******", "password": "******" } **Example response**: .. sourcecode:: http HTTP/1.1 200 OK Vary: Accept Content-Type: text/javascript { "token": "12343243243" } :arg username: username :arg password: password :statuscode 401: invalid credentials :statuscode 200: no error """ self.reqparse.add_argument('username', type=str, required=True, location='json') self.reqparse.add_argument('password', type=str, required=True, location='json') args = self.reqparse.parse_args() if '@' in args['username']: user = user_service.get_by_email(args['username']) else: user = user_service.get_by_username(args['username']) # default to local authentication if user and user.check_password(args['password']) and user.active: # Tell Flask-Principal the identity changed identity_changed.send(current_app._get_current_object(), identity=Identity(user.id)) metrics.send('login', 'counter', 1, metric_tags={'status': SUCCESS_METRIC_STATUS}) return dict(token=create_token(user)) # try ldap login if current_app.config.get("LDAP_AUTH"): try: ldap_principal = ldap.LdapPrincipal(args) user = ldap_principal.authenticate() if user and user.active: # Tell Flask-Principal the identity changed identity_changed.send(current_app._get_current_object(), identity=Identity(user.id)) metrics.send('login', 'counter', 1, metric_tags={'status': SUCCESS_METRIC_STATUS}) return dict(token=create_token(user)) except Exception as e: current_app.logger.error("ldap error: {0}".format(e)) ldap_message = 'ldap error: %s' % e metrics.send('login', 'counter', 1, metric_tags={'status': FAILURE_METRIC_STATUS}) return dict(message=ldap_message), 403 # if not valid user - no certificates for you metrics.send('login', 'counter', 1, metric_tags={'status': FAILURE_METRIC_STATUS}) return dict(message='The supplied credentials are invalid'), 403
def post(self): self.reqparse.add_argument('clientId', type=str, required=True, location='json') self.reqparse.add_argument('redirectUri', type=str, required=True, location='json') self.reqparse.add_argument('code', type=str, required=True, location='json') args = self.reqparse.parse_args() # take the information we have received from the provider to create a new request params = { 'grant_type': 'authorization_code', 'scope': 'openid email profile groups', 'redirect_uri': args['redirectUri'], 'code': args['code'], } # you can either discover these dynamically or simply configure them access_token_url = current_app.config.get('OAUTH2_ACCESS_TOKEN_URL') user_api_url = current_app.config.get('OAUTH2_USER_API_URL') verify_cert = current_app.config.get('OAUTH2_VERIFY_CERT', True) # the secret and cliendId will be given to you when you signup for the provider token = '{0}:{1}'.format(args['clientId'], current_app.config.get("OAUTH2_SECRET")) basic = base64.b64encode(bytes(token, 'utf-8')) headers = { 'Content-Type': 'application/x-www-form-urlencoded', 'authorization': 'basic {0}'.format(basic.decode('utf-8')) } # exchange authorization code for access token. # Try Params first r = requests.post(access_token_url, headers=headers, params=params, verify=verify_cert) if r.status_code == 400: r = requests.post(access_token_url, headers=headers, data=params, verify=verify_cert) id_token = r.json()['id_token'] access_token = r.json()['access_token'] # fetch token public key header_data = fetch_token_header(id_token) jwks_url = current_app.config.get('OAUTH2_JWKS_URL') # retrieve the key material as specified by the token header r = requests.get(jwks_url, verify=verify_cert) for key in r.json()['keys']: if key['kid'] == header_data['kid']: secret = get_rsa_public_key(key['n'], key['e']) algo = header_data['alg'] break else: return dict(message='Key not found'), 401 # validate your token based on the key it was signed with try: if sys.version_info >= (3, 0): jwt.decode(id_token, secret.decode('utf-8'), algorithms=[algo], audience=args['clientId']) else: jwt.decode(id_token, secret, algorithms=[algo], audience=args['clientId']) except jwt.DecodeError: return dict(message='Token is invalid'), 401 except jwt.ExpiredSignatureError: return dict(message='Token has expired'), 401 except jwt.InvalidTokenError: return dict(message='Token is invalid'), 401 headers = {'authorization': 'Bearer {0}'.format(access_token)} # retrieve information about the current user. r = requests.get(user_api_url, headers=headers, verify=verify_cert) profile = r.json() user = user_service.get_by_email(profile['email']) metrics.send('successful_login', 'counter', 1) # update with roles sent by identity provider roles = [] if 'roles' in profile: for group in profile['roles']: role = role_service.get_by_name(group) if not role: role = role_service.create( group, description= 'This is a group configured by identity provider', third_party=True) if not role.third_party: role = role_service.set_third_party( role.id, third_party_status=True) roles.append(role) role = role_service.get_by_name(profile['email']) if not role: role = role_service.create( profile['email'], description='This is a user specific role', third_party=True) if not role.third_party: role = role_service.set_third_party(role.id, third_party_status=True) roles.append(role) # if we get an sso user create them an account if not user: # every user is an operator (tied to a default role) if current_app.config.get('LEMUR_DEFAULT_ROLE'): v = role_service.get_by_name( current_app.config.get('LEMUR_DEFAULT_ROLE')) if not v.third_party: v = role_service.set_third_party(v.id, third_party_status=True) if v: roles.append(v) user = user_service.create(profile['name'], get_psuedo_random_string(), profile['email'], True, profile.get('thumbnailPhotoUrl'), roles) else: # we add 'lemur' specific roles, so they do not get marked as removed for ur in user.roles: if not ur.third_party: roles.append(ur) # update any changes to the user user_service.update( user.id, profile['name'], profile['email'], True, profile.get('thumbnailPhotoUrl' ), # incase profile isn't google+ enabled roles) # Tell Flask-Principal the identity changed identity_changed.send(current_app._get_current_object(), identity=Identity(user.id)) return dict(token=create_token(user))
def post(self): self.reqparse.add_argument("clientId", type=str, required=True, location="json") self.reqparse.add_argument("redirectUri", type=str, required=True, location="json") self.reqparse.add_argument("code", type=str, required=True, location="json") args = self.reqparse.parse_args() # take the information we have received from the provider to create a new request params = { "client_id": args["clientId"], "grant_type": "authorization_code", "scope": "openid email profile address", "redirect_uri": args["redirectUri"], "code": args["code"], } # you can either discover these dynamically or simply configure them access_token_url = current_app.config.get("PING_ACCESS_TOKEN_URL") user_api_url = current_app.config.get("PING_USER_API_URL") # the secret and cliendId will be given to you when you signup for the provider token = "{0}:{1}".format(args["clientId"], current_app.config.get("PING_SECRET")) if sys.version_info >= (3, 0): basic = base64.b64encode(bytes(token, "utf-8")) headers = {"authorization": "basic {0}".format(basic.decode("utf-8"))} else: basic = base64.b64encode(token, "utf-8") headers = {"authorization": "basic {0}".format(basic)} # exchange authorization code for access token. r = requests.post(access_token_url, headers=headers, params=params) id_token = r.json()["id_token"] access_token = r.json()["access_token"] # fetch token public key header_data = fetch_token_header(id_token) jwks_url = current_app.config.get("PING_JWKS_URL") # retrieve the key material as specified by the token header r = requests.get(jwks_url) for key in r.json()["keys"]: if key["kid"] == header_data["kid"]: secret = get_rsa_public_key(key["n"], key["e"]) algo = header_data["alg"] break else: return dict(message="Key not found"), 403 # validate your token based on the key it was signed with try: if sys.version_info >= (3, 0): jwt.decode(id_token, secret.decode("utf-8"), algorithms=[algo], audience=args["clientId"]) else: jwt.decode(id_token, secret, algorithms=[algo], audience=args["clientId"]) except jwt.DecodeError: return dict(message="Token is invalid"), 403 except jwt.ExpiredSignatureError: return dict(message="Token has expired"), 403 except jwt.InvalidTokenError: return dict(message="Token is invalid"), 403 user_params = dict(access_token=access_token, schema="profile") # retrieve information about the current user. r = requests.get(user_api_url, params=user_params) profile = r.json() user = user_service.get_by_email(profile["email"]) metrics.send("successful_login", "counter", 1) # update their google 'roles' roles = [] for group in profile["googleGroups"]: role = role_service.get_by_name(group) if not role: role = role_service.create(group, description="This is a google group based role created by Lemur") roles.append(role) role = role_service.get_by_name(profile["email"]) if not role: role = role_service.create(profile["email"], description="This is a user specific role") roles.append(role) # if we get an sso user create them an account if not user: # every user is an operator (tied to a default role) if current_app.config.get("LEMUR_DEFAULT_ROLE"): v = role_service.get_by_name(current_app.config.get("LEMUR_DEFAULT_ROLE")) if v: roles.append(v) user = user_service.create( profile["email"], get_psuedo_random_string(), profile["email"], True, profile.get("thumbnailPhotoUrl"), roles, ) else: # we add 'lemur' specific roles, so they do not get marked as removed for ur in user.roles: if ur.authority_id: roles.append(ur) # update any changes to the user user_service.update( user.id, profile["email"], profile["email"], True, profile.get("thumbnailPhotoUrl"), # incase profile isn't google+ enabled roles, ) # Tell Flask-Principal the identity changed identity_changed.send(current_app._get_current_object(), identity=Identity(user.id)) return dict(token=create_token(user))
def post(self): """ .. http:post:: /auth/login Login with username:password **Example request**: .. sourcecode:: http POST /auth/login HTTP/1.1 Host: example.com Accept: application/json, text/javascript Content-Type: application/json;charset=UTF-8 { "username": "******", "password": "******" } **Example response**: .. sourcecode:: http HTTP/1.1 200 OK Vary: Accept Content-Type: text/javascript { "token": "12343243243" } :arg username: username :arg password: password :statuscode 401: invalid credentials :statuscode 200: no error """ self.reqparse.add_argument("username", type=str, required=True, location="json") self.reqparse.add_argument("password", type=str, required=True, location="json") args = self.reqparse.parse_args() if "@" in args["username"]: user = user_service.get_by_email(args["username"]) else: user = user_service.get_by_username(args["username"]) # default to local authentication if user and user.check_password(args["password"]) and user.active: # Tell Flask-Principal the identity changed identity_changed.send(current_app._get_current_object(), identity=Identity(user.id)) metrics.send("login", "counter", 1, metric_tags={"status": SUCCESS_METRIC_STATUS}) return dict(token=create_token(user)) # try ldap login if current_app.config.get("LDAP_AUTH"): try: ldap_principal = ldap.LdapPrincipal(args) user = ldap_principal.authenticate() if user and user.active: # Tell Flask-Principal the identity changed identity_changed.send(current_app._get_current_object(), identity=Identity(user.id)) metrics.send( "login", "counter", 1, metric_tags={"status": SUCCESS_METRIC_STATUS}, ) return dict(token=create_token(user)) except Exception as e: current_app.logger.error("ldap error: {0}".format(e)) ldap_message = "ldap error: %s" % e metrics.send("login", "counter", 1, metric_tags={"status": FAILURE_METRIC_STATUS}) return dict(message=ldap_message), 403 # if not valid user - no certificates for you metrics.send("login", "counter", 1, metric_tags={"status": FAILURE_METRIC_STATUS}) return dict(message="The supplied credentials are invalid"), 403
def post(self): self.reqparse.add_argument('clientId', type=str, required=True, location='json') self.reqparse.add_argument('redirectUri', type=str, required=True, location='json') self.reqparse.add_argument('code', type=str, required=True, location='json') args = self.reqparse.parse_args() # take the information we have received from the provider to create a new request params = { 'client_id': args['clientId'], 'grant_type': 'authorization_code', 'scope': 'openid email profile address', 'redirect_uri': args['redirectUri'], 'code': args['code'] } # you can either discover these dynamically or simply configure them access_token_url = current_app.config.get('PING_ACCESS_TOKEN_URL') user_api_url = current_app.config.get('PING_USER_API_URL') # the secret and cliendId will be given to you when you signup for the provider basic = base64.b64encode('{0}:{1}'.format(args['clientId'], current_app.config.get("PING_SECRET"))) headers = {'Authorization': 'Basic {0}'.format(basic)} # exchange authorization code for access token. r = requests.post(access_token_url, headers=headers, params=params) id_token = r.json()['id_token'] access_token = r.json()['access_token'] # fetch token public key header_data = fetch_token_header(id_token) jwks_url = current_app.config.get('PING_JWKS_URL') # retrieve the key material as specified by the token header r = requests.get(jwks_url) for key in r.json()['keys']: if key['kid'] == header_data['kid']: secret = get_rsa_public_key(key['n'], key['e']) algo = header_data['alg'] break else: return dict(message='Key not found'), 403 # validate your token based on the key it was signed with try: jwt.decode(id_token, secret, algorithms=[algo], audience=args['clientId']) except jwt.DecodeError: return dict(message='Token is invalid'), 403 except jwt.ExpiredSignatureError: return dict(message='Token has expired'), 403 except jwt.InvalidTokenError: return dict(message='Token is invalid'), 403 user_params = dict(access_token=access_token, schema='profile') # retrieve information about the current user. r = requests.get(user_api_url, params=user_params) profile = r.json() user = user_service.get_by_email(profile['email']) # update their google 'roles' roles = [] for group in profile['googleGroups']: role = role_service.get_by_name(group) if not role: role = role_service.create(group, description='This is a google group based role created by Lemur') roles.append(role) # if we get an sso user create them an account # we still pick a random password in case sso is down if not user: # every user is an operator (tied to a default role) if current_app.config.get('LEMUR_DEFAULT_ROLE'): v = role_service.get_by_name(current_app.config.get('LEMUR_DEFAULT_ROLE')) if v: roles.append(v) user = user_service.create( profile['email'], get_psuedo_random_string(), profile['email'], True, profile.get('thumbnailPhotoUrl'), roles ) else: # we add 'lemur' specific roles, so they do not get marked as removed for ur in user.roles: if ur.authority_id: roles.append(ur) # update any changes to the user user_service.update( user.id, profile['email'], profile['email'], True, profile.get('thumbnailPhotoUrl'), # incase profile isn't google+ enabled roles ) # Tell Flask-Principal the identity changed identity_changed.send(current_app._get_current_object(), identity=Identity(user.id)) return dict(token=create_token(user))