Exemple #1
0
    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))
Exemple #2
0
    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
Exemple #3
0
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
Exemple #4
0
    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))
Exemple #5
0
    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
Exemple #6
0
    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)
Exemple #7
0
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
Exemple #8
0
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
Exemple #9
0
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
Exemple #10
0
    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}
        )
Exemple #11
0
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
Exemple #12
0
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
Exemple #13
0
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
Exemple #14
0
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
Exemple #15
0
    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})
Exemple #16
0
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)
Exemple #17
0
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)
Exemple #18
0
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)
Exemple #19
0
    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))
Exemple #20
0
    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
Exemple #21
0
    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
Exemple #22
0
    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))
Exemple #23
0
    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))
Exemple #24
0
    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
Exemple #25
0
    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))