def test_error_catching(self): validator = RequestValidator() server = Server(validator) server.catch_errors = True h, b, s = server.create_authorization_response('https://example.com') self.assertIn("server_error", b) self.assertEqual(s, 500)
def test_unavailability(self): validator = RequestValidator() server = Server(validator) server.available = False h, b, s = server.create_authorization_response('https://example.com') self.assertIn("temporarily_unavailable", b) self.assertEqual(s, 503)
class AuthorizationView(View): def __init__(self): validator = DjangoValidator() # TODO: this should probably be tunable through settings self._authorization_endpoint = Server(validator) self._error_uri = reverse('oauth2_error') def get(self, request, *args, **kwargs): uri, http_method, body, headers = extract_params(request) redirect_uri = request.GET.get('redirect_uri', None) log.debug('Found redirect uri %s.', redirect_uri) try: scopes, credentials = self._authorization_endpoint.validate_authorization_request( uri, http_method, body, headers) log.debug('Saving credentials to session, %r.', credentials) request.session['oauth2_credentials'] = credentials kwargs['scopes'] = scopes kwargs.update(credentials) actual_view = get_actual_authorization_view(request) log.debug('Invoking actual view method, %r.', actual_view) return actual_view(request, *args, **kwargs) except errors.FatalClientError as e: log.debug('Fatal client error, redirecting to error page.') return HttpResponseRedirect(e.in_uri(self._error_uri)) except errors.OAuth2Error as e: log.debug('Client error, redirecting back to client.') # TODO: remove after federico PR e.redirect_uri = redirect_uri or 'https://localhost' return HttpResponseRedirect(e.in_uri(e.redirect_uri)) @csrf_exempt def post(self, request, *args, **kwargs): uri, http_method, body, headers = extract_params(request) scopes, credentials = get_authorization(request) log.debug('Fetched credentials view, %r.', credentials) credentials.update(request.session.get('oauth2_credentials', {})) log.debug('Fetched credentials from session, %r.', credentials) redirect_uri = credentials.get('redirect_uri') log.debug('Found redirect uri %s.', redirect_uri) try: url, headers, body, status = self._authorization_endpoint.create_authorization_response( uri, http_method, body, headers, scopes, credentials) log.debug('Authorization successful, redirecting to client.') return HttpResponseRedirect(url) except errors.FatalClientError as e: log.debug('Fatal client error, redirecting to error page.') return HttpResponseRedirect(e.in_uri(self._error_uri)) except errors.OAuth2Error as e: log.debug('Client error, redirecting back to client.') return HttpResponseRedirect(e.in_uri(redirect_uri))
class IamRequestValidator(IRequestValidator): def __init__(self, validator: OauthlibRequestValidator): self._server = Server(validator) def validate_pre_auth_request(self, request: ff.Message): http_request = request.headers.get('http_request') return self._server.validate_authorization_request( f'{http_request["headers"]["Host"]}{http_request["url"]}', http_request['method'], '', http_request['headers']) def validate_post_auth_request(self, request: ff.Message): pass def create_response(self, request: ff.Message): return self._server.create_authorization_response( request.headers.get('uri'), request.headers.get('http_method'), request.to_dict(), request.headers)
class TestClaimsHandling(TestCase): DEFAULT_REDIRECT_URI = 'http://i.b./path' def set_scopes(self, scopes): def set_request_scopes(client_id, code, client, request): request.scopes = scopes return True return set_request_scopes def set_user(self, request): request.user = '******' request.client_id = 'bar' request.client = mock.MagicMock() request.client.client_id = 'mocked' return True def set_client(self, request): request.client = mock.MagicMock() request.client.client_id = 'mocked' return True def save_claims_with_code(self, client_id, code, request, *args, **kwargs): # a real validator would save the claims with the code during save_authorization_code() self.claims_from_auth_code_request = request.claims self.scopes = request.scopes.split() def retrieve_claims_saved_with_code(self, client_id, code, client, request, *args, **kwargs): request.claims = self.claims_from_auth_code_request request.scopes = self.scopes return True def save_claims_with_bearer_token(self, token, request, *args, **kwargs): # a real validator would save the claims with the access token during save_bearer_token() self.claims_saved_with_bearer_token = request.claims def setUp(self): self.validator = mock.MagicMock(spec=RequestValidator) self.validator.get_default_redirect_uri.return_value = TestClaimsHandling.DEFAULT_REDIRECT_URI self.validator.authenticate_client.side_effect = self.set_client self.validator.save_authorization_code.side_effect = self.save_claims_with_code self.validator.validate_code.side_effect = self.retrieve_claims_saved_with_code self.validator.save_token.side_effect = self.save_claims_with_bearer_token self.server = Server(self.validator) def test_claims_stored_on_code_creation(self): claims = { "id_token": { "claim_1": None, "claim_2": { "essential": True } }, "userinfo": { "claim_3": { "essential": True }, "claim_4": None } } claims_urlquoted = '%7B%22id_token%22%3A%20%7B%22claim_2%22%3A%20%7B%22essential%22%3A%20true%7D%2C%20%22claim_1%22%3A%20null%7D%2C%20%22userinfo%22%3A%20%7B%22claim_4%22%3A%20null%2C%20%22claim_3%22%3A%20%7B%22essential%22%3A%20true%7D%7D%7D' uri = 'http://example.com/path?client_id=abc&scope=openid+test_scope&response_type=code&claims=%s' h, b, s = self.server.create_authorization_response( uri % claims_urlquoted, scopes='openid test_scope') self.assertDictEqual(self.claims_from_auth_code_request, claims) code = get_query_credentials(h['Location'])['code'][0] token_uri = 'http://example.com/path' _, body, _ = self.server.create_token_response( token_uri, body='grant_type=authorization_code&code=%s' % code) self.assertDictEqual(self.claims_saved_with_bearer_token, claims) def test_invalid_claims(self): uri = 'http://example.com/path?client_id=abc&scope=openid+test_scope&response_type=code&claims=this-is-not-json' h, b, s = self.server.create_authorization_response( uri, scopes='openid test_scope') error = get_query_credentials(h['Location'])['error'][0] error_desc = get_query_credentials( h['Location'])['error_description'][0] self.assertEqual(error, 'invalid_request') self.assertEqual(error_desc, "Malformed claims parameter")
class AuthorizationEndpoint(object): def __init__(self, request): self.request = request self.validator = RequestValidator() self.server = Server(self.validator) @view_config(route_name='oauth2_authorization_endpoint', renderer='templates/application_authorization.pt', permission='add-authorized-app', request_method='GET') def get(self): uri, http_method, body, headers = extract_params(self.request) try: scopes, credentials = self.server.validate_authorization_request( uri, http_method, body, headers, ) app = self.validator.get_client(credentials['client_id']) try: auth_app = Session.query(AuthorizedApplication).filter( AuthorizedApplication.user == self.request.user, AuthorizedApplication.scope == scopes, AuthorizedApplication.redirect_uri == credentials['redirect_uri'], AuthorizedApplication.response_type == credentials['response_type'], AuthorizedApplication.application == app, ).one() except NoResultFound: auth_app = None if auth_app is not None: credentials['user'] = self.request.user server_response = self.server.create_authorization_response( uri, http_method, body, headers, scopes, credentials, ) return create_response(*server_response) else: authorship_information = app.user.email pretty_scopes = self.validator.get_pretty_scopes(scopes) return { 'response_type': credentials['response_type'], 'client_id': credentials['client_id'], 'redirect_uri': credentials['redirect_uri'], 'state': credentials['state'], 'scope': ' '.join(scopes), 'app': app, 'scopes': pretty_scopes, 'authorship_information': authorship_information, } except FatalClientError as e: return response_from_error(e) except OAuth2Error as e: return HTTPFound(e.in_uri(e.redirect_uri)) @view_config(route_name='oauth2_authorization_endpoint', permission='add-authorized-app', request_method='POST') def post(self): uri, http_method, body, headers = extract_params(self.request) redirect_uri = self.request.POST.get('redirect_uri') if 'submit' in self.request.POST: scope = self.request.POST.get('scope', '') scopes = scope.split() credentials = { 'client_id': self.request.POST.get('client_id'), 'redirect_uri': redirect_uri, 'response_type': self.request.POST.get('response_type'), 'state': self.request.POST.get('state'), 'user': self.request.user, } try: server_response = self.server.create_authorization_response( uri, http_method, body, headers, scopes, credentials, ) app = Session.query(Application).filter( Application.id == credentials['client_id'], ).one() try: auth_app = Session.query(AuthorizedApplication).filter( AuthorizedApplication.user == self.request.user, AuthorizedApplication.application == app, ).one() except NoResultFound: auth_app = AuthorizedApplication( user=self.request.user, application=app, ) auth_app.redirect_uri = credentials['redirect_uri'] auth_app.response_type = credentials['response_type'] auth_app.scope = scopes Session.add(auth_app) return create_response(*server_response) except FatalClientError as e: return response_from_error(e) elif 'cancel' in self.request.POST: e = AccessDeniedError() return HTTPFound(e.in_uri(redirect_uri))
class TestClaimsHandling(TestCase): DEFAULT_REDIRECT_URI = 'http://i.b./path' def set_scopes(self, scopes): def set_request_scopes(client_id, code, client, request): request.scopes = scopes return True return set_request_scopes def set_user(self, request): request.user = '******' request.client_id = 'bar' request.client = mock.MagicMock() request.client.client_id = 'mocked' return True def set_client(self, request): request.client = mock.MagicMock() request.client.client_id = 'mocked' return True def save_claims_with_code(self, client_id, code, request, *args, **kwargs): # a real validator would save the claims with the code during save_authorization_code() self.claims_from_auth_code_request = request.claims self.scopes = request.scopes.split() def retrieve_claims_saved_with_code(self, client_id, code, client, request, *args, **kwargs): request.claims = self.claims_from_auth_code_request request.scopes = self.scopes return True def save_claims_with_bearer_token(self, token, request, *args, **kwargs): # a real validator would save the claims with the access token during save_bearer_token() self.claims_saved_with_bearer_token = request.claims def setUp(self): self.validator = mock.MagicMock(spec=RequestValidator) self.validator.get_default_redirect_uri.return_value = TestClaimsHandling.DEFAULT_REDIRECT_URI self.validator.authenticate_client.side_effect = self.set_client self.validator.save_authorization_code.side_effect = self.save_claims_with_code self.validator.validate_code.side_effect = self.retrieve_claims_saved_with_code self.validator.save_token.side_effect = self.save_claims_with_bearer_token self.server = Server(self.validator) def test_claims_stored_on_code_creation(self): claims = { "id_token": { "claim_1": None, "claim_2": { "essential": True } }, "userinfo": { "claim_3": { "essential": True }, "claim_4": None } } claims_urlquoted='%7B%22id_token%22%3A%20%7B%22claim_2%22%3A%20%7B%22essential%22%3A%20true%7D%2C%20%22claim_1%22%3A%20null%7D%2C%20%22userinfo%22%3A%20%7B%22claim_4%22%3A%20null%2C%20%22claim_3%22%3A%20%7B%22essential%22%3A%20true%7D%7D%7D' uri = 'http://example.com/path?client_id=abc&scope=openid+test_scope&response_type=code&claims=%s' h, b, s = self.server.create_authorization_response(uri % claims_urlquoted, scopes='openid test_scope') self.assertDictEqual(self.claims_from_auth_code_request, claims) code = get_query_credentials(h['Location'])['code'][0] token_uri = 'http://example.com/path' _, body, _ = self.server.create_token_response(token_uri, body='grant_type=authorization_code&code=%s' % code) self.assertDictEqual(self.claims_saved_with_bearer_token, claims) def test_invalid_claims(self): uri = 'http://example.com/path?client_id=abc&scope=openid+test_scope&response_type=code&claims=this-is-not-json' h, b, s = self.server.create_authorization_response(uri, scopes='openid test_scope') error = get_query_credentials(h['Location'])['error'][0] error_desc = get_query_credentials(h['Location'])['error_description'][0] self.assertEqual(error, 'invalid_request') self.assertEqual(error_desc, "Malformed claims parameter")