def __check_entry(self, entry, allow_group): """ Checks an entry is in a valid format and expands groups. If groups are allowed, then inputting a group entry will result in the expanded group entries on the output. entry - The entry string to check. allow_group - Boolean, on whether to allow group names. Raises a ValueError if it isn't valid. Returns a list of entries. Each returned entry is a tuple of (auth_mode, auth_data). """ if entry == "TOKEN": return [(ACLManager.AUTH_MODE_TOKEN, None)] elif entry == "CERT": return [(ACLManager.AUTH_MODE_X509, None)] elif entry == "SESSION": return [(ACLManager.AUTH_MODE_SESSION, None)] elif entry == "ALL": return [(ACLManager.AUTH_MODE_ALLOW_ALL, None)] elif entry.startswith("CERT:"): raw_dn = entry.split(':', 1)[1] if not "=" in raw_dn: raise ValueError("Bad CERT DN in ACL rule: '%s'" % entry) return [(ACLManager.AUTH_MODE_X509, X509Utils.normalise_dn(raw_dn)) ] elif allow_group and entry.startswith("@"): group_name = entry[1:] if not group_name in self.__groups: raise ValueError("Unrecognised group used in ACL rule: %s" % \ group_name) return deepcopy(self.__groups[group_name]) raise ValueError("Invalid auth entry '%s'." % entry)
def __gen_req(self, path, method="GET", auth_mode=ACLManager.AUTH_MODE_NONE, auth_data=None, cert_ok=True, token_ok=True): """ Call self.__inst.check_request while generating a fake request with the given parameters (without using test_mode on the ACLManager). Returns True if the request was successful (i.e. access would have been allowed). """ app = Flask("ACLManagertest") app.secret_key = "TestKey" # Required for session support token_svc = FakeTokenSVC(token_ok) try: headers = {} enable_session = False if auth_mode == ACLManager.AUTH_MODE_X509: if cert_ok: headers['Ssl-Client-Verify'] = 'SUCCESS' else: headers['Ssl-Client-Verify'] = 'FAILED' headers['Ssl-Client-S-Dn'] = auth_data elif auth_mode == ACLManager.AUTH_MODE_TOKEN: headers['X-Token'] = json.dumps(auth_data) elif auth_mode == ACLManager.AUTH_MODE_SESSION: enable_session = True with app.test_request_context(path=path, method=method, headers=headers): if enable_session: set_session_state(True) # Prepare a standard looking request current_app.log = self.__log current_app.token_svc = token_svc request.uuid = "Test-Test-Test" # Call the check function self.__inst.check_request() # Check that request info was correctly propagated if auth_mode == ACLManager.AUTH_MODE_X509: norm_dn = X509Utils.normalise_dn(auth_data) self.assertEqual(request.dn, norm_dn) elif auth_mode == ACLManager.AUTH_MODE_TOKEN: if token_ok: self.assertEqual(request.token, auth_data) self.assertEqual(request.raw_token, json.dumps(auth_data)) self.assertTrue(request.token_ok) else: self.assertFalse(request.token_ok) elif auth_mode == ACLManager.AUTH_MODE_SESSION: self.assertTrue(request.session_ok) # Access was allowed (no exception raised) return True except Forbidden: # Access was denied (Forbidden exception thrown) return False
def __get_fake_request_auth(self): """ Fills the request object with te test (fake) authentication details. """ if self.__test_mode == ACLManager.AUTH_MODE_X509: request.dn = X509Utils.normalise_dn(self.__test_data) elif self.__test_mode == ACLManager.AUTH_MODE_TOKEN: request.token = self.__test_data request.raw_token = self.__test_data request.token_ok = True elif self.__test_mode == ACLManager.AUTH_MODE_SESSION: request.session_ok = True
def __check_test_mode(self, auth_mode, auth_data): """ Helper function for testing test_mode. """ self.__inst.test_mode(auth_mode, auth_data) app = Flask("ACLManagertest") with app.test_request_context(path="/test", method="GET"): request.uuid = "Test-Test-Test" # Call the check function self.__inst.check_request() # Check that request info was correctly propagated if auth_mode == ACLManager.AUTH_MODE_X509: norm_dn = X509Utils.normalise_dn(auth_data) self.assertEqual(request.dn, norm_dn) elif auth_mode == ACLManager.AUTH_MODE_TOKEN: self.assertEqual(request.token, auth_data) self.assertEqual(request.raw_token, auth_data) self.assertTrue(request.token_ok) elif auth_mode == ACLManager.AUTH_MODE_SESSION: self.assertTrue(request.session_ok)
def __get_real_request_auth(): """ Fills the details of the presented credentials into the request object. """ # Cert auth if 'Ssl-Client-Verify' in request.headers \ and 'Ssl-Client-S-Dn' in request.headers: # Request has client cert if request.headers['Ssl-Client-Verify'] == 'SUCCESS': raw_dn = request.headers['Ssl-Client-S-Dn'] request.dn = X509Utils.normalise_dn(raw_dn) # Token Auth if 'X-Token' in request.headers: raw_token = request.headers['X-Token'] try: token_value = current_app.token_svc.check(raw_token) # Check if this looks like a standard token with an expiry value if isinstance(token_value, dict): if 'expiry' in token_value: exp_str = token_value['expiry'] exp_value = datetime.strptime(exp_str, '%Y-%m-%dT%H:%M:%S.%f') if exp_value < datetime.utcnow(): # Token has already expired current_app.log.info( "Request %s token has expired (at %s)", request.uuid, exp_str) return "403 Expired Token", 403 request.token = token_value request.raw_token = raw_token request.token_ok = True except ValueError: # Token decoding failed, it is probably corrupt or has been # tampered with. current_app.log.info("Request %s token validation failed.", request.uuid) return "403 Invalid Token", 403 if 'logged_in' in session: if session['logged_in']: request.session_ok = True
def test_dn_normalisation(self): """ Test the X509 DN normalisation function. """ # Test DN in expected output format TEST_DN = "C=XX, L=YY, CN=Test CA" # Test both RFC and OpenSSL style DNs with increasing amounts of space # All should match the TEST_DN after normalisation. self.assertEqual(X509Utils.normalise_dn(TEST_DN), TEST_DN) self.assertEqual(X509Utils.normalise_dn("/C=XX/L=YY/CN=Test CA"), TEST_DN) self.assertEqual( X509Utils.normalise_dn("/C=XX / L = YY / CN = Test CA "), TEST_DN) # Check that leading space doesn't upset the algorithm self.assertEqual( X509Utils.normalise_dn(" / C =XX / L = YY / CN = Test CA "), TEST_DN) self.assertEqual( X509Utils.normalise_dn("C = XX, L = YY, CN = Test CA"), TEST_DN) self.assertEqual( X509Utils.normalise_dn("C = XX, L = YY, CN = Test CA "), TEST_DN) self.assertEqual( X509Utils.normalise_dn( " C = XX, L = YY, CN = Test CA"), TEST_DN)