def test_owncloud(self): # prepare service storage = Storage() redirect = "https://10.14.29.60/owncloud/index.php/apps/rds/oauth" owncloud = OAuth2Service( servicename="owncloud-local", implements=["metadata"], authorize_url= "https://10.14.29.60/owncloud/index.php/apps/oauth2/authorize?response_type=code&client_id={}&redirect_uri={}" .format(os.getenv("OWNCLOUD_OAUTH_CLIENT_ID"), redirect), refresh_url= "https://10.14.29.60/owncloud/index.php/apps/oauth2/api/v1/token", client_id=os.getenv("OWNCLOUD_OAUTH_CLIENT_ID"), client_secret=os.getenv("OWNCLOUD_OAUTH_CLIENT_SECRET"), ) storage.addService(owncloud) # prepare user, which wants to make the whole oauth workflow user1 = User("user") token1 = Token(user1, owncloud, "user") storage.addUser(user1) storage.addTokenToUser(token1, user1) def get_access_token(user, token): nonlocal owncloud, storage self.driver.get(owncloud.authorize_url) if self.driver.current_url.startswith( "https://10.14.29.60/owncloud/index.php/login"): # it redirects to login form field_username = self.driver.find_element_by_xpath( '//*[@id="user"]') field_password = self.driver.find_element_by_xpath( '//*[@id="password"]') field_username.clear() field_username.send_keys(user.username) field_password.clear() field_password.send_keys(token.access_token) old_url = self.driver.current_url url = self.driver.current_url field_password.send_keys(Keys.RETURN) retry = 0 while old_url == url and retry < 5: sleep(1) retry += 1 url = self.driver.current_url logger.info("url: {}".format(url)) if retry >= 5: raise Exception("url not redirect!") btn = self.driver.find_element_by_xpath( "/html/body/div[1]/div/span/form/button") old_url = self.driver.current_url url = self.driver.current_url btn.click() retry = 0 while old_url == url and retry < 5: sleep(1) retry += 1 url = self.driver.current_url logger.info("url: {}".format(url)) if retry >= 5: raise Exception("url not redirect!") self.driver.delete_all_cookies() # remove all cookies from urllib.parse import urlparse, parse_qs query = urlparse(url).query logger.info("query: {}".format(query)) parse = parse_qs(query) logger.info("parse: {}".format(parse)) code = parse["code"] data = { "grant_type": "authorization_code", "code": code, "redirect_uri": redirect, } req = requests.post( owncloud.refresh_url, data=data, auth=(owncloud.client_id, owncloud.client_secret), verify=False, ).json() oauthtoken = OAuth2Token( user, token.service, req["access_token"], req["refresh_token"], datetime.now() + timedelta(seconds=req["expires_in"]), ) return oauthtoken oauthtoken1 = get_access_token(user1, token1) storage.addTokenToUser(oauthtoken1, user1, Force=True) ######## test a refresh token ####### # prepare user, which wants to get a refresh token oauthuser2 = User("user_refresh") # check if there is already a file, which has an oauth2token to reuse it. oauthtoken2 = None filepath = "https://zivgitlab.uni-muenster.de/{}/{}/-/jobs/artifacts/{}/raw/{}/user_refresh.token?job_token={}&job={}".format( os.getenv("CI_PROJECT_NAMESPACE"), os.getenv("CI_PROJECT_NAME"), os.getenv("CI_COMMIT_REF_NAME"), os.getenv("FOLDER"), os.getenv("CI_JOB_TOKEN"), os.getenv("CI_JOB_NAME"), ) try: headers = {"JOB-TOKEN": os.getenv("CI_JOB_TOKEN")} req = requests.get(filepath, headers=headers) if req.status_code != 200: raise Exception( "Artifact not found, filepath: {filepath}, headers: {headers}" ) try: oauthtoken2 = initialize_object_from_json(req.text) except Exception as e: raise Exception(f"{str(e)} + \n req: {req.text}") except Exception as e: logger.error(e) logger.warning( "No refresh token from previous test run was found, so we collect a new one. \nFilepath: {}" .format(filepath)) # initialize like user1 with password token2 = Token(oauthuser2, owncloud, "user_refresh") # generate an oauthtoken like before and overwrite oauthtoken1 oauthtoken2 = get_access_token(oauthuser2, token2) storage.addUser(oauthuser2) storage.addTokenToUser(oauthtoken2, oauthuser2) # try to refresh it now storage.refresh_service(owncloud) tokens = storage.getTokens(oauthuser2) checkToken = tokens[0] self.assertEqual(checkToken, oauthtoken2) # safe the current oauthtoken for reuse to test refresh token after a bigger period. with open("user_refresh.token", "w") as f: f.write(json.dumps(checkToken))
class TestStorageService(unittest.TestCase): def setUp(self): self.empty_storage = Storage() self.user1 = User("Max Mustermann") self.user2 = User("Mimi Mimikri") self.user3 = User("Karla Kolumda") self.service1 = LoginService(servicename="MusterService", implements=["metadata"]) self.service2 = LoginService(servicename="BetonService", implements=["metadata"]) self.service3 = LoginService(servicename="FahrService", implements=["metadata"]) # owncloud self.oauthservice1 = OAuth2Service.from_service( self.service1, f"{pact_host_fqdn}/owncloud/index.php/apps/oauth2/authorize", f"{pact_host_fqdn}/owncloud/index.php/apps/oauth2/api/v1/token", "ABC", "XYZ", ) # zenodo self.oauthservice2 = OAuth2Service.from_service( self.service2, f"{pact_host_fqdn}/oauth/authorize", f"{pact_host_fqdn}/oauth/token", "DEF", "UVW", ) self.oauthservice3 = OAuth2Service.from_service( self.service3, f"{pact_host_fqdn}/api/authorize", f"{pact_host_fqdn}/api/token", "GHI", "MNO", ) self.token1 = Token(self.user1, self.service1, "ABC") self.token_like_token1 = Token(self.user1, self.service1, "DEF") self.token2 = Token(self.user2, self.service2, "XYZ") self.token3 = Token(self.user1, self.service3, "GHI") self.oauthtoken1 = OAuth2Token(self.user3, self.oauthservice1, "ABC", "X_ABC") self.oauthtoken_like_token1 = OAuth2Token(self.user3, self.oauthservice1, "ABC", "X_DEF") self.oauthtoken2 = OAuth2Token(self.user1, self.oauthservice2, "XYZ", "X_XYZ") self.oauthtoken3 = OAuth2Token(self.user3, self.oauthservice3, "GHI", "X_GHI") self.oauthtoken4 = OAuth2Token(self.user1, self.oauthservice1, "AMZ", "X_AMZ") self.services = [ self.service1, self.service2, self.service3, self.oauthservice1, self.oauthservice2, self.oauthservice3, ] self.filled_storage_without_tokens = Storage() self.filled_storage_without_tokens.addUser(self.user1) self.filled_storage_without_tokens.addUser(self.user2) self.filled_storage_without_tokens.addUser(self.user3) self.filled_storage = Storage() # user1 is filled with mixed token and oauth2token self.filled_storage.addUser(self.user1) self.filled_storage.addService(self.oauthservice1) self.filled_storage.addService(self.oauthservice2) self.filled_storage.addService(self.oauthservice3) self.filled_storage.addTokenToUser(self.token1, self.user1) self.filled_storage.addTokenToUser(self.token3, self.user1) self.filled_storage.addTokenToUser(self.oauthtoken2, self.user1) # user2 is only filled with token self.filled_storage.addUser(self.user2) self.filled_storage.addTokenToUser(self.token2, self.user2) # user3 is only filled with oauth2token self.filled_storage.addUser(self.user3) self.filled_storage.addTokenToUser(self.oauthtoken1, self.user3) self.filled_storage.addTokenToUser(self.oauthtoken3, self.user3) def test_internal_find_services(self): self.assertEqual( self.empty_storage.internal_find_service(self.service1.servicename, [self.service1]), 0, ) self.assertEqual( self.empty_storage.internal_find_service( self.service1.servicename, [self.service1, self.service2]), 0, ) self.assertEqual( self.empty_storage.internal_find_service( self.service1.servicename, [self.service2, self.service1]), 1, ) self.assertEqual( self.empty_storage.internal_find_service( self.service2.servicename, [self.service1, self.service2]), 1, ) self.assertEqual( self.empty_storage.internal_find_service( self.oauthservice1.servicename, [self.oauthservice1]), 0, ) self.assertEqual( self.empty_storage.internal_find_service( self.oauthservice1.servicename, [self.oauthservice1, self.oauthservice2]), 0, ) self.assertEqual( self.empty_storage.internal_find_service( self.oauthservice1.servicename, [self.oauthservice2, self.oauthservice1]), 1, ) self.assertEqual( self.empty_storage.internal_find_service( self.oauthservice2.servicename, [self.oauthservice1, self.oauthservice2]), 1, ) self.assertEqual( self.empty_storage.internal_find_service( self.oauthservice2.servicename, [self.service1, self.oauthservice2]), 1, ) with self.assertRaises(ValueError): self.empty_storage.internal_find_service(self.service1.servicename, [self.service2]) with self.assertRaises(ValueError): self.empty_storage.internal_find_service( self.service1.servicename, [self.service2, self.service3]) with self.assertRaises(ValueError): self.empty_storage.internal_find_service( self.service1.servicename, [self.oauthservice2, self.oauthservice3]) with self.assertRaises(ValueError): self.empty_storage.internal_find_service( self.oauthservice1.servicename, [self.service2, self.service3]) def test_refresh_all_tokens(self): # works without any tokens self.assertFalse( self.filled_storage_without_tokens.refresh_service(self.service1)) self.assertFalse( self.filled_storage_without_tokens.refresh_services( self.oauthservice1)) self.assertFalse( self.filled_storage_without_tokens.refresh_services(self.services)) # false because only a simple service self.assertFalse(self.filled_storage.refresh_service(self.service1), msg=self.filled_storage) # works with a request to a provider expected_user = self.user3 expected_service = self.oauthservice1 expires_in = 3600 # example taken from https://github.com/owncloud/oauth2 json_expected = { "access_token": "1vtnuo1NkIsbndAjVnhl7y0wJha59JyaAiFIVQDvcBY2uvKmj5EPBEhss0pauzdQ", "token_type": "Bearer", "expires_in": expires_in, "refresh_token": "7y0wJuvKmj5E1vjVnhlPBEhha59JyaAiFIVQDvcBY2ss0pauzdQtnuo1NkIsbndA", "user_id": expected_user.username, "message_url": f"{pact_host_fqdn}/owncloud/index.php/apps/oauth2/authorization-successful", } from base64 import b64encode auth = f"{expected_service.client_id}:{expected_service.client_secret}" b64 = b64encode(auth.encode("utf-8")).decode("utf-8") pact.given( "Username can refresh given oauth2token to service", username=expected_service.client_id, service=expected_service, ).upon_receiving("An invalid response.").with_request( "POST", "/oauth/token").will_respond_with(404, body={}) pact.given( "Username can refresh given oauth2token to service", username=expected_service.client_id, service=expected_service, ).upon_receiving("A valid refresh token response.").with_request( "POST", "/owncloud/index.php/apps/oauth2/api/v1/token", headers={ "Authorization": f"Basic {b64}" }, ).will_respond_with(200, body=json_expected) pact.given("Username can refresh given oauth2token to service" ).upon_receiving("An invalid response for another service." ).with_request( "POST", "/api/token").will_respond_with( 404, body={}) result = None with pact: result = self.filled_storage.refresh_service(expected_service) self.assertTrue(result) # test for missing service self.assertFalse( self.filled_storage.refresh_services([ BaseService(servicename="NotFoundService", implements=["metadata"]) ])) """ Currently not implemented and no idea how to solve. def test_valid_token(self): # Test, if token can be used in service self.assertTrue(self.service1.is_valid(self.token1, self.user1)) self.assertTrue(self.oauthservice1.is_valid( self.oauthtoken1, self.user1)) self.assertFalse(self.service1.is_valid(self.token2, self.user2)) self.assertFalse(self.oauthservice1.is_valid( self.oauthtoken2, self.user2)) # try to use the token to raise an exception with self.assertRaises(TokenNotValidError): self.oauthservice1.status(self.token1)""" def test_storage_refresh_save_mechanism(self): expires_in = 3600 expected = OAuth2Token(self.user1, self.oauthservice1, "ABC", "XYZ") expected._expiration_date = datetime.fromtimestamp(time() + expires_in) # example taken from https://github.com/owncloud/oauth2 json_expected = { "access_token": expected.access_token, "token_type": "Bearer", "expires_in": expires_in, "refresh_token": expected.refresh_token, "user_id": self.user1.username, "message_url": f"{pact_host_fqdn}/owncloud/index.php/apps/oauth2/authorization-successful", } pact.given( "Storage can refresh given oauth2token and saves it in storage" ).upon_receiving( "A valid refresh token response with a higher expiration date." ).with_request( "POST", "/owncloud/index.php/apps/oauth2/api/v1/token").will_respond_with( 200, body=json_expected) result = None with pact: self.empty_storage.addService(self.oauthservice1) self.empty_storage.addUser(self.user1) self.empty_storage.addTokenToUser(self.oauthtoken4, self.user1) self.empty_storage.refresh_service(self.oauthservice1) result = self.empty_storage.getTokens() # there should only be one element in list, so it is ours self.assertEqual(len(result), 1) self.assertEqual( result[0], expected, msg=f"\nresult: {result[0]}\nexpected: {expected}") self.assertGreaterEqual(result[0].expiration_date, expected.expiration_date) def test_refresh_oauth2token(self): expires_in = 3600 expected = self.oauthtoken1 expected._access_token = "XYZABCTESTKORREKT" expected._refresh_token = "PLASDPJAPSJFSNIDFN" expected._exiration_date = datetime.fromtimestamp(time() + expires_in) # example taken from https://github.com/owncloud/oauth2 json_expected = { "access_token": expected.access_token, "token_type": "Bearer", "expires_in": expires_in, "refresh_token": expected.refresh_token, "user_id": expected.user.username, "message_url": f"{pact_host_fqdn}/owncloud/index.php/apps/oauth2/authorization-successful", } pact.given( "Username can refresh given oauth2token", username=self.user1.username ).upon_receiving("A valid refresh token response.").with_request( "POST", "/owncloud/index.php/apps/oauth2/api/v1/token").will_respond_with( 200, body=json_expected) result = None with pact: result = self.oauthtoken1.refresh() self.assertEqual(result, expected, msg=f"\nresult: {result}\nexpected: {expected}") """ obsolete # this needs to be here, because it counts the given interactions, # so if this is missing, you get an error, when you do the following assertion. pact.given( "Username can refresh given oauth2token", username=self.user1.username ).upon_receiving( "A valid refresh token response." ).with_request( "POST", "/owncloud/index.php/apps/oauth2/api/v1/token" ).will_respond_with(200, body=json_expected) with self.assertRaises(TokenNotValidError): with pact: self.oauthservice1.refresh(self.token1) """ pact.given( "Username can't refresh given oauth2token", username=self.user1.username ).upon_receiving("A bad request was made.").with_request( "POST", "/owncloud/index.php/apps/oauth2/api/v1/token").will_respond_with( 400, body=json_expected) with self.assertRaises(OAuth2UnsuccessfulResponseError): with pact: self.oauthservice1.refresh(self.oauthtoken1) self.make_bad_request_for_oauth_provider("invalid_request", OAuth2InvalidRequestError) self.make_bad_request_for_oauth_provider("invalid_client", OAuth2InvalidClientError) self.make_bad_request_for_oauth_provider("invalid_grant", OAuth2InvalidGrantError) self.make_bad_request_for_oauth_provider("unauthorized_client", OAuth2UnauthorizedClient) self.make_bad_request_for_oauth_provider("unsupported_grant_type", OAuth2UnsupportedGrantType) def make_bad_request_for_oauth_provider(self, error_code, error): """ For convenience. """ json_expected = {"error": error_code} pact.given("Username made a bad request", username=self.user1.username).upon_receiving( f"A bad request with error {error_code} was made." ).with_request( "POST", "/owncloud/index.php/apps/oauth2/api/v1/token" ).will_respond_with(400, body=json_expected) with self.assertRaises(error): with pact: self.oauthservice1.refresh(self.oauthtoken1) def test_service_list(self): expected = [] # there should be no services self.assertEqual(self.empty_storage.getServices(), expected) # add an invalid service with self.assertRaises(ValueError): self.empty_storage.addService(123) with self.assertRaises(ValueError): self.empty_storage.addService(self.token1) with self.assertRaises(ValueError): self.empty_storage.addService(self.user1) with self.assertRaises(ValueError): self.empty_storage.getService(123) with self.assertRaises(ValueError): self.empty_storage.getService(self.token1) with self.assertRaises(ValueError): self.empty_storage.getService(self.user1) # add a service expected.append(self.service1) self.empty_storage.addService(self.service1) self.assertEqual(self.empty_storage.getServices(), expected) self.assertIsInstance( self.empty_storage.getService(self.service1.servicename), BaseService) self.assertEqual( self.empty_storage.getService(self.service1.servicename), self.service1, msg=self.empty_storage.getServices(), ) self.assertEqual(self.empty_storage.getService(self.service1), self.service1) from RDS.ServiceException import ServiceExistsAlreadyError with self.assertRaises(ServiceExistsAlreadyError): self.empty_storage.addService(self.service1) # add oauthservice for a already exists service, first with error, then with force with self.assertRaises(ServiceExistsAlreadyError): self.empty_storage.addService(self.oauthservice1) expected = [self.oauthservice1] self.empty_storage.addService(self.oauthservice1, Force=True) self.assertEqual(self.empty_storage.getServices(), expected) # add the next service expected.append(self.service2) self.empty_storage.addService(self.service2) self.assertEqual(self.empty_storage.getServices(), expected) # remove a not existing service self.assertFalse(self.empty_storage.removeService(self.service3)) self.assertTrue(self.empty_storage.removeService(self.service2)) self.assertTrue( self.empty_storage.removeService(self.service1), msg="{}".format(",".join(map(str, self.empty_storage._services))), ) # should be empty now self.assertEqual(self.empty_storage.getServices(), [])