Example #1
0
    def auth_complete(self, *args, **kwargs):
        """Completes login process, must return user instance"""
        self.process_error(self.data)
        try:
            response = self.request_access_token(
                self.ACCESS_TOKEN_URL,
                data=self.auth_complete_params(self.validate_state()),
                headers=self.auth_headers(),
                method=self.ACCESS_TOKEN_METHOD)
        except HTTPError as err:
            if err.response.status_code == 400:
                raise AuthCanceled(self)
            else:
                raise
        except KeyError:
            raise AuthUnknownError(self)

        if 'errcode' in response:
            return HttpResponse(json.dumps(response))
            # raise AuthCanceled(self)
        self.process_error(response)
        return self.do_auth(response['access_token'],
                            response=response,
                            *args,
                            **kwargs)
Example #2
0
    def get_apple_jwk(self):
        """Returns an iterable of apple jwk strings."""
        keys = self.get_json(url=self.JWK_URL).get("keys")
        if not isinstance(keys, list) or not keys:
            raise AuthCanceled("Invalid jwk response")

        return (json.dumps(key) for key in keys)
Example #3
0
    def decode_id_token(self, id_token):
        '''Decode and validate JWT token from apple and return payload including user data.'''
        if not id_token:
            raise AuthCanceled("Missing id_token parameter")

        kid = jwt.get_unverified_header(id_token).get('kid')
        public_key = RSAAlgorithm.from_jwk(self.get_apple_jwk(kid))
        try:
            decoded = jwt.decode(
                id_token,
                key=public_key,
                audience=self.setting("CLIENT"),
                algorithm="RS256",
            )
        except PyJWTError:
            raise AuthCanceled("Token validation failed")

        return decoded
Example #4
0
    def decode_id_token(self, id_token):
        '''Decode and validate JWT token from apple and return payload including user data.'''
        if not id_token:
            raise AuthCanceled('Missing id_token parameter')

        for jwk_string in self.get_apple_jwk():
            public_key = RSAAlgorithm.from_jwk(jwk_string)
            try:
                decoded = jwt.decode(id_token,
                                     key=public_key,
                                     audience=self.setting('CLIENT'),
                                     algorithm='RS256')
                break
            except PyJWTError:
                pass
        else:
            raise AuthCanceled('Token validation failed')

        return decoded
Example #5
0
    def get_apple_jwk(self, kid=None):
        '''Return requested Apple public key or all available.'''
        keys = self.get_json(url=self.JWK_URL).get("keys")

        if not isinstance(keys, list) or not keys:
            raise AuthCanceled("Invalid jwk response")

        if kid:
            return json.dumps([key for key in keys if key['kid'] == kid][0])
        else:
            return (json.dumps(key) for key in keys)
Example #6
0
    def do_auth(self, access_token, *args, **kwargs):
        response = kwargs.pop('response', None) or {}
        jwt_string = response.get(self.TOKEN_KEY) or access_token
        if not jwt_string:
            raise AuthCanceled("Missing id_token parameter")

        decoded_data = self.decode_id_token(jwt_string)
        return super(AppleIdAuth, self).do_auth(access_token,
                                                response=decoded_data,
                                                *args,
                                                **kwargs)
    def auth_complete(self, *args, **kwargs):
        """Completes loging process, must return user instance"""
        self.process_error(self.data)

        appid, secret = self.get_key_and_secret()
        try:
            if WEIXIN_WORK_SP:
                response = self.request_access_token(
                    self.access_token_url(appid, secret),
                    json=self.auth_complete_params(self.validate_state()),
                    headers={
                        'Content-Type': 'application/json',
                        'Accept': 'application/json'
                    },
                    method=self.ACCESS_TOKEN_METHOD)
            else:
                response = self.request_access_token(
                    self.access_token_url(appid, secret),
                    data=self.auth_complete_params(self.validate_state()),
                    headers=self.auth_headers(),
                    method=self.ACCESS_TOKEN_METHOD)
        except HTTPError as err:
            if err.response.status_code == 400:
                raise AuthCanceled(self, response=err.response)
            else:
                raise
        except KeyError:
            raise AuthUnknownError(self)

        try:
            if response['errmsg'] != 'ok':
                raise AuthCanceled(self)
        except KeyError:
            pass  # assume response is ok if 'errmsg' key not found

        self.process_error(response)

        access_token = response[
            'provider_access_token'] if WEIXIN_WORK_SP else response[
                'access_token']
        return self.do_auth(access_token, response=response, *args, **kwargs)
Example #8
0
    def test_auth_complete_cancelation(self, super_auth_complete,
                                       validate_state):
        user = mommy.make(User)
        backend = RESTStateBackend()
        backend.session = {'_user_id': user.id}
        super_auth_complete.side_effect = AuthCanceled(backend)
        response = backend.auth_complete()
        assert response['location'] == reverse('user:redirect_to_app')
        validate_state.assert_called_once_with()
        super_auth_complete.assert_called_once_with(user=user)

        error_obj = AuthError.objects.last()
        assert error_obj.provider == 'rest-state'
        assert error_obj.message == 'Authentication process canceled'
        assert error_obj.user == user
Example #9
0
 def process_error(self, data):
     super().process_error(data)
     if data.get('serviceErrorCode'):
         raise AuthCanceled(self, data.get('message') or data.get('status'))