Beispiel #1
0
def test_validate_redirect(app, sqlalchemy_datastore):
    """
    Test various possible URLs that urlsplit() shows as relative but
    many browsers will interpret as absolute - and thus have a
    open-redirect vulnerability. Note this vulnerability only
    is viable if the application sets autocorrect_location_header = False
    """
    init_app_with_options(app, sqlalchemy_datastore)
    with app.test_request_context("http://localhost:5001/login"):
        assert not validate_redirect_url("\\\\\\github.com")
        assert not validate_redirect_url(" //github.com")
        assert not validate_redirect_url("\t//github.com")
        assert not validate_redirect_url("//github.com")  # this is normal urlsplit
Beispiel #2
0
    def post(self):
        if "aad" not in current_app.config.get("ACTIVE_PROVIDERS"):
            return "AzureAD is not enabled in the config.  See the ACTIVE_PROVIDERS section.", 404

        default_state = 'clientId,{client_id},redirectUri,{redirectUri},return_to,{return_to}'.format(
            client_id=current_app.config.get('AAD_CLIENT_ID'),
            redirectUri=current_app.config.get('AAD_REDIRECT_URI'),
            return_to=current_app.config.get('WEB_PATH'))
        self.reqparse.add_argument('code', type=str, required=True)
        self.reqparse.add_argument('id_token', type=str, required=True)
        self.reqparse.add_argument('state',
                                   type=str,
                                   required=False,
                                   default=default_state)

        args = self.reqparse.parse_args()
        client_id = args['state'].split(',')[1]
        redirect_uri = args['state'].split(',')[3]
        return_to = args['state'].split(',')[5]
        id_token = args['id_token']

        if not validate_redirect_url(return_to):
            return_to = current_app.config.get('WEB_PATH')

        # fetch token public key
        jwks_url = current_app.config.get('AAD_JWKS_URL')

        # Validate id_token and extract username (email)
        username = self.validate_id_token(id_token, client_id, jwks_url)

        user = setup_user(username, '',
                          current_app.config.get('AAD_DEFAULT_ROLE', 'View'))

        # Tell Flask-Principal the identity changed
        identity_changed.send(current_app._get_current_object(),
                              identity=Identity(user.id))
        login_user(user)
        db.session.commit()
        db.session.refresh(user)

        return redirect(return_to, code=302)
Beispiel #3
0
    def post(self):
        if "aad" not in current_app.config.get("ACTIVE_PROVIDERS"):
            return "AzureAD is not enabled in the config.  See the ACTIVE_PROVIDERS section.", 404

        default_state = 'clientId,{client_id},redirectUri,{redirectUri},return_to,{return_to}'.format(
            client_id=current_app.config.get('AAD_CLIENT_ID'),
            redirectUri=current_app.config.get('AAD_REDIRECT_URI'),
            return_to=current_app.config.get('WEB_PATH')
        )
        self.reqparse.add_argument('code', type=str, required=True)
        self.reqparse.add_argument('id_token', type=str, required=True)
        self.reqparse.add_argument('state', type=str, required=False, default=default_state)

        args = self.reqparse.parse_args()
        client_id = args['state'].split(',')[1]
        redirect_uri = args['state'].split(',')[3]
        return_to = args['state'].split(',')[5]
        id_token = args['id_token']

        if not validate_redirect_url(return_to):
            return_to = current_app.config.get('WEB_PATH')

        # fetch token public key
        jwks_url = current_app.config.get('AAD_JWKS_URL')

        # Validate id_token and extract username (email)
        username = self.validate_id_token(id_token, client_id, jwks_url)

        user = setup_user(username, '', current_app.config.get('AAD_DEFAULT_ROLE', 'View'))

        # Tell Flask-Principal the identity changed
        identity_changed.send(current_app._get_current_object(), identity=Identity(user.id))
        login_user(user)
        db.session.commit()
        db.session.refresh(user)

        return redirect(return_to, code=302)
Beispiel #4
0
 def validate_next(self, field):
     from flask_security.utils import validate_redirect_url
     if field.data and not validate_redirect_url(field.data):
         field.data = ''
         flash('INVALID_REDIRECT')
         raise ValidationError('INVALID_REDIRECT')
Beispiel #5
0
    def post(self):
        if "ping" not in current_app.config.get("ACTIVE_PROVIDERS"):
            return "Ping is not enabled in the config.  See the ACTIVE_PROVIDERS section.", 404

        default_state = 'clientId,{client_id},redirectUri,{redirectUri},return_to,{return_to}'.format(
            client_id=current_app.config.get('PING_CLIENT_ID'),
            redirectUri=current_app.config.get('PING_REDIRECT_URI'),
            return_to=current_app.config.get('WEB_PATH'))
        self.reqparse.add_argument('code', type=str, required=True)
        self.reqparse.add_argument('state',
                                   type=str,
                                   required=False,
                                   default=default_state)

        args = self.reqparse.parse_args()
        client_id = args['state'].split(',')[1]
        redirect_uri = args['state'].split(',')[3]
        return_to = args['state'].split(',')[5]

        if not validate_redirect_url(return_to):
            return_to = current_app.config.get('WEB_PATH')

        # take the information we have received from the provider to create a new request
        params = {
            'client_id': client_id,
            'grant_type': 'authorization_code',
            'scope': 'openid email profile address',
            'redirect_uri': redirect_uri,
            '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(
            bytes('{0}:{1}'.format(client_id,
                                   current_app.config.get("PING_SECRET"))))
        headers = {'Authorization': 'Basic {0}'.format(basic.decode('utf-8'))}

        # 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_payload(id_token)[0]
        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:
            current_app.logger.debug(id_token)
            current_app.logger.debug(secret)
            current_app.logger.debug(algo)
            jwt.decode(id_token,
                       secret.decode('utf-8'),
                       algorithms=[algo],
                       audience=client_id)
        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.query.filter(User.email == profile['email']).first()

        # if we get an sso user create them an account
        if not user:
            user = User(email=profile['email'],
                        active=True,
                        role='View'
                        # profile_picture=profile.get('thumbnailPhotoUrl')
                        )
            db.session.add(user)
            db.session.commit()
            db.session.refresh(user)

        # Tell Flask-Principal the identity changed
        identity_changed.send(current_app._get_current_object(),
                              identity=Identity(user.id))
        login_user(user)

        return redirect(return_to, code=302)
Beispiel #6
0
    def post(self):
        if "google" not in current_app.config.get("ACTIVE_PROVIDERS"):
            return "Google is not enabled in the config.  See the ACTIVE_PROVIDERS section.", 404

        default_state = 'clientId,{client_id},redirectUri,{redirectUri},return_to,{return_to}'.format(
            client_id=current_app.config.get("GOOGLE_CLIENT_ID"),
            redirectUri=api.url_for(Google),
            return_to=current_app.config.get('WEB_PATH'))
        self.reqparse.add_argument('code', type=str, required=True)
        self.reqparse.add_argument('state',
                                   type=str,
                                   required=False,
                                   default=default_state)

        args = self.reqparse.parse_args()
        client_id = args['state'].split(',')[1]
        redirect_uri = args['state'].split(',')[3]
        return_to = args['state'].split(',')[5]

        if not validate_redirect_url(return_to):
            return_to = current_app.config.get('WEB_PATH')

        access_token_url = 'https://accounts.google.com/o/oauth2/token'
        people_api_url = 'https://www.googleapis.com/plus/v1/people/me/openIdConnect'

        args = self.reqparse.parse_args()

        # Step 1. Exchange authorization code for access token
        payload = {
            'client_id': client_id,
            'grant_type': 'authorization_code',
            'redirect_uri': redirect_uri,
            'code': args['code'],
            'client_secret': current_app.config.get('GOOGLE_SECRET')
        }

        r = requests.post(access_token_url, data=payload)
        token = r.json()

        # Step 1bis. Validate (some information of) the id token (if necessary)
        google_hosted_domain = current_app.config.get("GOOGLE_HOSTED_DOMAIN")
        if google_hosted_domain is not None:
            current_app.logger.debug(
                'We need to verify that the token was issued for this hosted domain: %s '
                % (google_hosted_domain))

            # Get the JSON Web Token
            id_token = r.json()['id_token']
            current_app.logger.debug('The id_token is: %s' % (id_token))

            # Extract the payload
            (header_data, payload_data) = fetch_token_header_payload(id_token)
            current_app.logger.debug('id_token.header_data: %s' %
                                     (header_data))
            current_app.logger.debug('id_token.payload_data: %s' %
                                     (payload_data))

            token_hd = payload_data.get('hd')
            if token_hd != google_hosted_domain:
                current_app.logger.debug('Verification failed: %s != %s' %
                                         (token_hd, google_hosted_domain))
                return dict(message='Token is invalid %s' % token), 403
            current_app.logger.debug('Verification passed')

        # 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.query.filter(User.email == profile['email']).first()

        # if we get an sso user create them an account
        if not user:
            user = User(email=profile['email'],
                        active=True,
                        role='View'
                        # profile_picture=profile.get('thumbnailPhotoUrl')
                        )
            db.session.add(user)
            db.session.commit()
            db.session.refresh(user)

        # Tell Flask-Principal the identity changed
        identity_changed.send(current_app._get_current_object(),
                              identity=Identity(user.id))
        login_user(user)

        return redirect(return_to, code=302)
Beispiel #7
0
    def post(self):
        if "ping" not in current_app.config.get("ACTIVE_PROVIDERS"):
            return "Ping is not enabled in the config.  See the ACTIVE_PROVIDERS section.", 404

        default_state = 'clientId,{client_id},redirectUri,{redirectUri},return_to,{return_to}'.format(
            client_id=current_app.config.get('PING_CLIENT_ID'),
            redirectUri=current_app.config.get('PING_REDIRECT_URI'),
            return_to=current_app.config.get('WEB_PATH')
        )
        self.reqparse.add_argument('code', type=str, required=True)
        self.reqparse.add_argument('state', type=str, required=False, default=default_state)

        args = self.reqparse.parse_args()
        client_id = args['state'].split(',')[1]
        redirect_uri = args['state'].split(',')[3]
        return_to = args['state'].split(',')[5]

        if not validate_redirect_url(return_to):
            return_to = current_app.config.get('WEB_PATH')

        # take the information we have received from the provider to create a new request
        params = {
            'client_id': client_id,
            'grant_type': 'authorization_code',
            'scope': 'openid email profile address',
            'redirect_uri': redirect_uri,
            '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(bytes('{0}:{1}'.format(client_id, current_app.config.get("PING_SECRET"))))
        headers = {'Authorization': 'Basic {0}'.format(basic.decode('utf-8'))}

        # 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_payload(id_token)[0]
        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.decode('utf-8'), algorithms=[algo], audience=client_id)
        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 = setup_user(
            profile.get('email'),
            profile.get('groups', profile.get('googleGroups', [])),
            current_app.config.get('PING_DEFAULT_ROLE', 'View'))

        # Tell Flask-Principal the identity changed
        identity_changed.send(current_app._get_current_object(), identity=Identity(user.id))
        login_user(user)
        db.session.commit()
        db.session.refresh(user)

        return redirect(return_to, code=302)
Beispiel #8
0
    def post(self):
        if "google" not in current_app.config.get("ACTIVE_PROVIDERS"):
            return "Google is not enabled in the config.  See the ACTIVE_PROVIDERS section.", 404

        default_state = 'clientId,{client_id},redirectUri,{redirectUri},return_to,{return_to}'.format(
            client_id=current_app.config.get("GOOGLE_CLIENT_ID"),
            redirectUri=api.url_for(Google),
            return_to=current_app.config.get('WEB_PATH')
        )
        self.reqparse.add_argument('code', type=str, required=True)
        self.reqparse.add_argument('state', type=str, required=False, default=default_state)

        args = self.reqparse.parse_args()
        client_id = args['state'].split(',')[1]
        redirect_uri = args['state'].split(',')[3]
        return_to = args['state'].split(',')[5]

        if not validate_redirect_url(return_to):
            return_to = current_app.config.get('WEB_PATH')

        access_token_url = 'https://accounts.google.com/o/oauth2/token'
        people_api_url = 'https://www.googleapis.com/plus/v1/people/me/openIdConnect'

        args = self.reqparse.parse_args()

        # Step 1. Exchange authorization code for access token
        payload = {
            'client_id': client_id,
            'grant_type': 'authorization_code',
            'redirect_uri': redirect_uri,
            'code': args['code'],
            'client_secret': current_app.config.get('GOOGLE_SECRET')
        }

        r = requests.post(access_token_url, data=payload)
        token = r.json()

        # Step 1bis. Validate (some information of) the id token (if necessary)
        google_hosted_domain = current_app.config.get("GOOGLE_HOSTED_DOMAIN")
        if google_hosted_domain is not None:
            current_app.logger.debug('We need to verify that the token was issued for this hosted domain: %s ' % (google_hosted_domain))

	    # Get the JSON Web Token
            id_token = r.json()['id_token']
            current_app.logger.debug('The id_token is: %s' % (id_token))

            # Extract the payload
            (header_data, payload_data) = fetch_token_header_payload(id_token)
            current_app.logger.debug('id_token.header_data: %s' % (header_data))
            current_app.logger.debug('id_token.payload_data: %s' % (payload_data))

            token_hd = payload_data.get('hd')
            if token_hd != google_hosted_domain:
                current_app.logger.debug('Verification failed: %s != %s' % (token_hd, google_hosted_domain))
                return dict(message='Token is invalid %s' % token), 403
            current_app.logger.debug('Verification passed')

        # 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 = setup_user(profile.get('email'), profile.get('groups', []), current_app.config.get('GOOGLE_DEFAULT_ROLE', 'View'))

        # Tell Flask-Principal the identity changed
        identity_changed.send(current_app._get_current_object(), identity=Identity(user.id))
        login_user(user)
        db.session.commit()
        db.session.refresh(user)

        return redirect(return_to, code=302)
Beispiel #9
0
 def validate_next(self, field):
     if field.data and not validate_redirect_url(field.data):
         field.data = ''
         flash(*get_message('INVALID_REDIRECT'))
         raise ValidationError(get_message('INVALID_REDIRECT')[0])
Beispiel #10
0
    def post(self):
        if "google" not in current_app.config.get("ACTIVE_PROVIDERS"):
            return "Google is not enabled in the config.  See the ACTIVE_PROVIDERS section.", 404

        default_state = 'clientId,{client_id},redirectUri,{redirectUri},return_to,{return_to}'.format(
            client_id=current_app.config.get("GOOGLE_CLIENT_ID"),
            redirectUri=api.url_for(Google),
            return_to=current_app.config.get('WEB_PATH')
        )
        self.reqparse.add_argument('code', type=str, required=True)
        self.reqparse.add_argument('state', type=str, required=False, default=default_state)

        args = self.reqparse.parse_args()
        client_id = args['state'].split(',')[1]
        redirect_uri = args['state'].split(',')[3]
        return_to = args['state'].split(',')[5]

        if not validate_redirect_url(return_to):
            return_to = current_app.config.get('WEB_PATH')

        access_token_url = 'https://accounts.google.com/o/oauth2/token'
        people_api_url = 'https://www.googleapis.com/plus/v1/people/me/openIdConnect'

        args = self.reqparse.parse_args()

        # Step 1. Exchange authorization code for access token
        payload = {
            'client_id': client_id,
            'grant_type': 'authorization_code',
            'redirect_uri': redirect_uri,
            '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.query.filter(User.email == profile['email']).first()

        # if we get an sso user create them an account
        if not user:
            user = User(
                email=profile['email'],
                active=True,
                role='View'
                # profile_picture=profile.get('thumbnailPhotoUrl')
            )
            db.session.add(user)
            db.session.commit()
            db.session.refresh(user)

        # Tell Flask-Principal the identity changed
        identity_changed.send(current_app._get_current_object(), identity=Identity(user.id))
        login_user(user)

        return redirect(return_to, code=302)
    def post(self):
        if "okta" not in current_app.config.get("ACTIVE_PROVIDERS"):
            return "Okta is not enabled in the config.  See the ACTIVE_PROVIDERS section.", 404

        default_state = 'clientId,{client_id},redirectUri,{redirectUri},return_to,{return_to}'.format(
            client_id=current_app.config.get('OKTA_CLIENT_ID'),
            redirectUri=current_app.config.get('OKTA_REDIRECT_URI'),
            return_to=current_app.config.get('WEB_PATH'))

        self.reqparse.add_argument('code', type=str, required=False)
        self.reqparse.add_argument('state',
                                   type=str,
                                   required=False,
                                   default=default_state)

        args = self.reqparse.parse_args()
        client_id = args['state'].split(',')[1]
        redirect_uri = args['state'].split(',')[3]
        return_to = args['state'].split(',')[5]
        code = args['code']

        if not validate_redirect_url(return_to):
            return_to = current_app.config.get('WEB_PATH')

        basic = base64.b64encode(
            bytes('{0}:{1}'.format(
                client_id, current_app.config.get("OKTA_CLIENT_SECRET"))))
        headers = {
            'Authorization': 'Basic {0}'.format(basic.decode('utf-8')),
            'Content-Type': 'application/x-www-form-urlencoded',
        }

        access_token_url = current_app.config.get('OKTA_TOKEN_ENDPOINT')
        params = {
            'code': code,
            'grant_type': 'authorization_code',
            'redirect_uri': redirect_uri
        }

        r = requests.post(access_token_url, headers=headers, params=params)
        id_token = r.json()['id_token']

        # fetch token public key
        header_data = fetch_token_header_payload(id_token)[0]
        jwks_url = current_app.config.get('OKTA_JWKS_URI')

        # 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:
            valid_token = jwt.decode(id_token,
                                     secret.decode('utf-8'),
                                     algorithms=[algo],
                                     audience=client_id)
        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 = setup_user(valid_token['email'], '',
                          current_app.config.get('OKTA_DEFAULT_ROLE', 'View'))

        # Tell Flask-Principal the identity changed
        identity_changed.send(current_app._get_current_object(),
                              identity=Identity(user.id))
        login_user(user)
        db.session.commit()
        db.session.refresh(user)

        return redirect(return_to, code=302)
    def post(self):
        if "google" not in current_app.config.get("ACTIVE_PROVIDERS"):
            return "Google is not enabled in the config.  See the ACTIVE_PROVIDERS section.", 404

        default_state = 'clientId,{client_id},redirectUri,{redirectUri},return_to,{return_to}'.format(
            client_id=current_app.config.get("GOOGLE_CLIENT_ID"),
            redirectUri=api.url_for(Google),
            return_to=current_app.config.get('WEB_PATH'))
        self.reqparse.add_argument('code', type=str, required=True)
        self.reqparse.add_argument('state',
                                   type=str,
                                   required=False,
                                   default=default_state)

        args = self.reqparse.parse_args()
        client_id = args['state'].split(',')[1]
        redirect_uri = args['state'].split(',')[3]
        return_to = args['state'].split(',')[5]

        if not validate_redirect_url(return_to):
            return_to = current_app.config.get('WEB_PATH')

        access_token_url = 'https://accounts.google.com/o/oauth2/token'

        if self._isAuthMethod('directory'):
            auth_method_api_url = 'https://www.googleapis.com/admin/directory/v1/groups'
        elif self._isAuthMethod('people'):
            auth_method_api_url = 'https://www.googleapis.com/userinfo/v2/me'
        else:
            return dict(message='Auth method not supported'), 403

        args = self.reqparse.parse_args()

        # Step 1. Exchange authorization code for access token
        payload = {
            'client_id': client_id,
            'grant_type': 'authorization_code',
            'redirect_uri': redirect_uri,
            'code': args['code'],
            'client_secret': current_app.config.get('GOOGLE_SECRET')
        }

        r = requests.post(access_token_url, data=payload)
        token = r.json()

        if 'error' in token:
            raise UnableToIssueGoogleAuthToken(token['error'])

        # Step 1bis. Validate (some information of) the id token (if necessary)
        google_hosted_domain = current_app.config.get("GOOGLE_HOSTED_DOMAIN")
        userKey = None
        if google_hosted_domain is not None:
            current_app.logger.debug(
                'We need to verify that the token was issued for this hosted domain: %s '
                % (google_hosted_domain))

            # Get the JSON Web Token
            id_token = token['id_token']
            current_app.logger.debug('The id_token is: %s' % (id_token))

            # Extract the payload
            (header_data, payload_data) = fetch_token_header_payload(id_token)
            current_app.logger.debug('id_token.header_data: %s' %
                                     (header_data))
            current_app.logger.debug('id_token.payload_data: %s' %
                                     (payload_data))

            token_hd = payload_data.get('hd')
            if token_hd != google_hosted_domain:
                current_app.logger.debug('Verification failed: %s != %s' %
                                         (token_hd, google_hosted_domain))
                return dict(message='Token is invalid %s' % token), 403
            current_app.logger.debug('Verification passed')
            userKey = payload_data.get('email')

        # Step 2. Retrieve information about the current user
        if self._isAuthMethod('directory'):
            if not self.credentials.token:
                current_app.logger.debug(
                    'Attempting refresh credentials to obtain initial access token'
                )
                self.credentials.refresh(GoogleAuthTransportRequest())

            headers = {
                'Authorization': 'Bearer {0}'.format(self.credentials.token)
            }

            api_url = "%(url)s?domain=%(domain)s&userKey=%(email)s&fields=groups/email" % {
                'url': auth_method_api_url,
                'domain': google_hosted_domain,
                'email': userKey
            }
            r = requests.get(api_url, headers=headers)
            groups = r.json()
            current_app.logger.debug('authenticated user with groups: %s' %
                                     groups)
            if len(groups.get('groups', [])) == 0:
                return dict(message='Groups association is invald for %s' %
                            userKey), 403
            else:
                groupsEmails = [o['email'] for o in groups.get('groups', [])]
                default_role = current_app.config.get('GOOGLE_DEFAULT_ROLE',
                                                      'View')

                if current_app.config.get('GOOGLE_ADMIN_ROLE_GROUP_NAME') and \
                        current_app.config.get('GOOGLE_ADMIN_ROLE_GROUP_NAME') in groupsEmails:
                    default_role = "Admin"

                current_app.logger.debug('Authenticating user %s as role %s' %
                                         (userKey, default_role))
                user = setup_user(userKey, groupsEmails, default_role)

                # Tell Flask-Principal the identity changed
                identity_changed.send(current_app._get_current_object(),
                                      identity=Identity(user.id))
                login_user(user)
                db.session.commit()
                db.session.refresh(user)

                return redirect(return_to, code=302)
        elif self._isAuthMethod('people'):
            headers = {
                'Authorization': 'Bearer {0}'.format(token['access_token'])
            }

            r = requests.get(auth_method_api_url, headers=headers)
            r.raise_for_status()
            profile = r.json()

            if 'email' not in profile:
                raise UnableToAccessGoogleEmail()

            user = setup_user(
                profile.get('email'), profile.get('groups', []),
                current_app.config.get('GOOGLE_DEFAULT_ROLE', 'View'))

            # Tell Flask-Principal the identity changed
            identity_changed.send(current_app._get_current_object(),
                                  identity=Identity(user.id))
            login_user(user)
            db.session.commit()
            db.session.refresh(user)

            return redirect(return_to, code=302)
Beispiel #13
0
 def validate_next(self, field):
     from flask_security.utils import validate_redirect_url
     if field.data and not validate_redirect_url(field.data):
         field.data = ''
         flash('INVALID_REDIRECT')
         raise ValidationError('INVALID_REDIRECT')