def test_perform_service_validate_separate_url(self): cas_client = CASClient('https://dummy.url', validate_url='https://validate.url') assert not cas_client.headers with mock.patch('cas_client.CASClient._perform_get') as m: m.return_value = self.response_text response = cas_client.perform_service_validate( ticket='FOO', service_url='BAR', ) m.assert_called_once_with( 'https://validate.url/cas/serviceValidate?ticket=FOO&service=BAR', headers=None) self.assertTrue(response.success) self.assertEqual( response.attributes, { u'i2a2characteristics': u'0,3592,2000', u'puid': u'0012345678', u'firstname': u'Jeffrey A', u'lastname': u'Ott', u'fullname': u'Jeffrey A Ott', u'email': u'*****@*****.**', }) self.assertEqual(response.response_type, 'authenticationSuccess') self.assertEqual(response.user, 'jott')
def test_get_destroy_other_sessions_url(self): cas_client = CASClient('https://dummy.url') service_url = 'https://app.url' url = cas_client.get_destroy_other_sessions_url( service_url=service_url) self.assertEqual( url, 'https://dummy.url/cas/destroy-other-sessions?service=https://app.url' )
class CASAuthProvider(AuthProvider): """Provides authentication using CAS The type name to instantiate this provider is *cas*. """ def __init__(self, *args, **kwargs): super(CASAuthProvider, self).__init__(*args, **kwargs) self.settings.setdefault('callback_uri', '/cas_auth/{}'.format(self.name)) if not self.settings.get('cas_url_base'): raise MultipassException( "`cas_url_base` must be specified in the provider settings") self.cas_client = CASClient(self.settings['cas_url_base'], auth_prefix='') self.cas_endpoint = '_flaskmultipass_cas_' + self.name current_app.add_url_rule(self.settings['callback_uri'], self.cas_endpoint, self._authorize_callback, methods=('GET', 'POST')) @property def cas_callback_url(self): return request.url_root + self.settings['callback_uri'] def initiate_external_login(self): cas_login_url = self.cas_client.get_login_url( service_url=self.cas_callback_url) return redirect(cas_login_url) def process_logout(self, return_url): cas_logout_url = self.cas_client.get_logout_url( service_url=self.cas_callback_url) return redirect(cas_logout_url) def _make_auth_info(self, resp): return AuthInfo(self, token=resp[self.settings['token_field']]) @login_view def _authorize_callback(self): ticket = request.args.get('ticket') if not ticket: raise AuthenticationFailed('ticket is not provided') cas_response = self.cas_client.perform_service_validate( ticket=ticket, service_url=self.cas_callback_url, ) if cas_response and cas_response.success: auth_info = cas_response.attributes auth_info['_username'] = cas_response.user return self.multipass.handle_auth_success( AuthInfo(self, **auth_info)) raise AuthenticationFailed("CAS result: Access denied")
def test_parse_logout_request(self): cas_client = CASClient('https://dummy.url') parsed_message = cas_client.parse_logout_request(self.slo_text) self.assertEqual( parsed_message, { 'ID': '[RANDOM ID]', 'IssueInstant': '[CURRENT DATE/TIME]', 'Version': '2.0', 'session_index': '[SESSION IDENTIFIER]', 'xmlns:saml': 'urn:oasis:names:tc:SAML:2.0:assertion', 'xmlns:samlp': 'urn:oasis:names:tc:SAML:2.0:protocol', })
def test_parse_logout_request_2(self): cas_client = CASClient('https://dummy.url') parsed_message = cas_client.parse_logout_request(self.slo_text_2) self.assertEqual( parsed_message, { 'ID': '935a2d0c-4026-481e-be3d-20a1b2cdd553', 'IssueInstant': '2016-04-08 00:40:55 +0000', 'Version': '2.0', 'session_index': 'ST-14600760351898-0B3lSFt2jOWSbgQ377B4CtbD9uq0MXR9kG23vAuH', 'xmlns:saml': 'urn:oasis:names:tc:SAML:2.0:assertion', 'xmlns:samlp': 'urn:oasis:names:tc:SAML:2.0:protocol', })
def get(self, request, *args): # 统一身份认证登录 ticket = request.GET.get('ticket') cas_url = 'https://passport.ustc.edu.cn' app_login_url = 'http://home.ustc.edu.cn/~via' cas_client = CASClient(cas_url, auth_prefix='') if ticket: try: cas_response = cas_client.perform_service_validate( ticket=ticket, service_url=app_login_url, ) except Exception: # CAS server is currently broken, try again later. return Response('CAS server is currently broken, try again later.', status.HTTP_503_SERVICE_UNAVAILABLE) if cas_response and cas_response.success: student_id = cas_response.user try: user = User.objects.get(student_id=student_id) # request.session['username'] = user.username # request.session['userid'] = user.id # request.session['isadmin'] = user.is_superuser login(request, user) except: gid = cas_response.data.get('attributes', {}).get('gid') username = str(gid) while True: try: user = {'username':username, 'student_id':student_id, 'password':student_id} serializer = UserSerializer(data=user) serializer.is_valid(True) serializer.save() user = User.objects.get(student_id=student_id) # request.session['username'] = user.username # request.session['userid'] = user.id # request.session['isadmin'] = user.is_superuser login(request, user) break except Exception: # import sys # exc_type, exc_obj, exc_tb = sys.exc_info() # print(f"{exc_type.__name__}: {exc_obj}") username = "".join(random.choices('0123456789abcdefghijklmnopqrstuvwxyz@.+-_', k=10)) # rep = Response('OK', status.HTTP_200_OK) # 更换为 rep = redirect('home') rep = redirect('http://202.38.75.113/') rep.set_cookie('userid', user.id) return rep cas_login_url = cas_client.get_login_url(service_url=app_login_url) return redirect(cas_login_url)
def test_acquire_auth_token_ticket_headers_init(self): class MockResponse(object): text = '{"ticket": "FOO"}' cas_client = CASClient('https://dummy.url', headers={'baz': 'quux'}) assert cas_client.headers == {'baz': 'quux'} with mock.patch('requests.post') as m: m.return_value = MockResponse() cas_client.acquire_auth_token_ticket() m.assert_called_with( 'https://dummy.url/cas/api/auth_token_tickets', headers={'baz': 'quux'}, verify=False, )
def test_parse_logout_request(self): cas_client = CASClient("dummy.url") parsed_message = cas_client.parse_logout_request(self.slo_text) self.assertEqual( parsed_message, { "ID": "[RANDOM ID]", "IssueInstant": "[CURRENT DATE/TIME]", "Version": "2.0", "session_index": "[SESSION IDENTIFIER]", "xmlns:saml": "urn:oasis:names:tc:SAML:2.0:assertion", "xmlns:samlp": "urn:oasis:names:tc:SAML:2.0:protocol", }, )
def __init__(self, *args, **kwargs): super(CASAuthProvider, self).__init__(*args, **kwargs) self.settings.setdefault('callback_uri', '/cas_auth/{}'.format(self.name)) if not self.settings.get('cas_url_base'): raise MultipassException( "`cas_url_base` must be specified in the provider settings") self.cas_client = CASClient(self.settings['cas_url_base'], auth_prefix='') self.cas_endpoint = '_flaskmultipass_cas_' + self.name current_app.add_url_rule(self.settings['callback_uri'], self.cas_endpoint, self._authorize_callback, methods=('GET', 'POST'))
def test_parse_logout_request_2(self): cas_client = CASClient("dummy.url") parsed_message = cas_client.parse_logout_request(self.slo_text_2) self.assertEqual( parsed_message, { "ID": "935a2d0c-4026-481e-be3d-20a1b2cdd553", "IssueInstant": "2016-04-08 00:40:55 +0000", "Version": "2.0", "session_index": "ST-14600760351898-0B3lSFt2jOWSbgQ377B4CtbD9uq0MXR9kG23vAuH", "xmlns:saml": "urn:oasis:names:tc:SAML:2.0:assertion", "xmlns:samlp": "urn:oasis:names:tc:SAML:2.0:protocol", }, )
def logout(): """Logs a user out""" #CAS client init cas_client = CASClient(app.config['CAS_SERVER_URL'], app.config['CAS_SERVICE_URL'], verify_certificates=True) # destroy the session cas_ticket = session.get('cas_ticket', None) cortex.lib.user.clear_session() if cas_ticket is not None: # Tell cas about the logout return redirect(cas_client.get_logout_url()) else: return login()
def test_acquire_auth_token_ticket_no_headers(self): class MockResponse(object): text = '{"ticket": "FOO"}' cas_client = CASClient('https://dummy.url') assert not cas_client.headers with mock.patch('requests.post') as m: m.return_value = MockResponse() cas_client.acquire_auth_token_ticket() m.assert_called_with( 'https://dummy.url/cas/api/auth_token_tickets', data=None, headers=None, verify=False, )
def test_get_auth_token_logic_url(self): cas_client = CASClient("dummy.url") auth_token_ticket = "AT-1234" authenticator = "my_company_ldap" username = "******" service_url = "example.com" private_key_filepath = "test_private_key.pem" with open(private_key_filepath, "r") as file_pointer: private_key = file_pointer.read() cas_client.get_auth_token_login_url( auth_token_ticket=auth_token_ticket, authenticator=authenticator, private_key=private_key, service_url=service_url, username=username, )
def test_perform_service_validate_headers_init(self): class MockResponse(object): text = self.response_text cas_client = CASClient('https://dummy.url', headers={'baz': 'quux'}) assert cas_client.headers == {'baz': 'quux'} with mock.patch('requests.get') as m: m.return_value = MockResponse() cas_client.perform_service_validate( ticket='FOO', service_url='BAR', ) m.assert_called_with( 'https://dummy.url/cas/serviceValidate?ticket=FOO&service=BAR', headers={'baz': 'quux'}, verify=False, )
def _get_test_api_url(self): cas_client = CASClient('https://dummy.url') api_resource = 'do_something_useful' auth_token_ticket = 'ATT-1234' authenticator = 'my_company_ldap' with open(self.private_key_filepath, 'r') as file_pointer: private_key = file_pointer.read() service_url = 'https://example.com' kwargs = { 'and': 'another_thing', 'you': 'should_know', } return cas_client.get_api_url(api_resource=api_resource, auth_token_ticket=auth_token_ticket, authenticator=authenticator, private_key=private_key, service_url=service_url, **kwargs)
def test_perform_service_validate(self): cas_client = CASClient("dummy.url") cas_client._request_cas_response = lambda url: self.response_text response = cas_client.perform_service_validate(ticket="FOO", service_url="BAR") self.assertTrue(response.success) self.assertEqual( response.attributes, { u"i2a2characteristics": u"0,3592,2000", u"puid": u"0012345678", u"firstname": u"Jeffrey A", u"lastname": u"Ott", u"fullname": u"Jeffrey A Ott", u"email": u"*****@*****.**", }, ) self.assertEqual(response.response_type, "authenticationSuccess") self.assertEqual(response.user, "jott")
def test_get_api_url(self): cas_client = CASClient('https://dummy.url') api_resource = 'do_something_useful' auth_token_ticket = 'ATT-1234' authenticator = 'my_company_ldap' with open(self.private_key_filepath, 'r') as file_pointer: private_key = file_pointer.read() service_url = 'https://example.com' kwargs = { 'and': 'another_thing', 'you': 'should_know', } url = cas_client.get_api_url(api_resource=api_resource, auth_token_ticket=auth_token_ticket, authenticator=authenticator, private_key=private_key, service_url=service_url, **kwargs) query_string = url.partition('?')[-1] query_parameters = { key: value[0] for key, value in parse_qs(query_string).items() } assert query_parameters == { 'at': ('eyJhbmQiOiAiYW5vdGhlcl90aGluZyIsICJhdXRoZW50aWNhdG9yIjogIm15' 'X2NvbXBhbnlfbGRhcCIsICJ0aWNrZXQiOiAiQVRULTEyMzQiLCAieW91Ijog' 'InNob3VsZF9rbm93In0='), 'ats': ('FISMx+fVfKKzI160MQRMauKdeqBRzzg+Ihwh0WqhqcnW4d+S0IyrTg6/oY1a' 'wGvhBGrSMzOEBfYyihj5SxmLMr+xWm5Ndt+m0WcjuOR2GEwtEimIbbEQslCu' 'f+//tG2u3UacStBRctt/cWnIGlW9cIPlUgU4iVVQtpbC7DdJc9+2rwzN10jV' '36JUwAWWT3iQseTiyMy+Bbuu1bzTcdtKvBdHTnCwcu1m9vkQraH/ZuVbYVMB' 'jZC1s5lXECLN+fnC00laglYmgQ1w59EoQIXuaaHFqgq+zRvRxm4r0ASG5F0D' 'bPT0fEDihQulSAbyOY5/6nhkFq6NYlJADKuGchFusk9D3Pcgs2KyEW3xvBb4' 'ZArn2oaI8sxjOYUXutf1xe5MBGy8oTW+3QbHVv+hzXOrwJXsbSz6bx3gmDYb' 'bDilhbRgPQeTH17IwqArrVgnjgcAMoDk6cTqU548S19KMc8B99pVZ7JMM5Ls' 'uKx/ZWUF0naXFeuEaFJ5TdaO6HhhiRhUAEwlnwTQwwJuR1VtcYx4z3Lb5NhN' 'CtH658M8acru4Dv4jV5NC3IPJcCijKGVjZQ0K6GrD863fr3usnH1gvnTzNgJ' '1jijF4FmyIr8E9kpNM5Mk7D0AqSGCC2nZcu/r4+2rcLiq9XxViv3jpe44alQ' 'RjhkcqcbkcJvnhckfgjrU7w='), 'service': 'https://example.com', }
def cas(): """Handles the login page, logging a user in on correct authentication.""" #CAS client init cas_client = CASClient(app.config['CAS_SERVER_URL'], app.config['CAS_SERVICE_URL'], verify_certificates=True) #SLO if request.method == 'POST' and session.get( 'cas_ticket') is not None and 'logoutRequest' in request.form: #check the verify the ticket to prevent cross orign attacks message = cas_client.parse_logout_request( request.form.get('logoutRequest')) if message.get('session_index', None) == session.get('cas_ticket'): cortex.lib.user.clear_session() return ('', 200) abort(400) # If the user is already logged in, just redirect them to their dashboard if cortex.lib.user.is_logged_in(): return redirect(url_for('dashboard')) ticket = request.args.get('ticket', None) if ticket is not None: try: cas_response = cas_client.perform_service_validate(ticket=ticket) except Exception: return root() if cas_response and cas_response.success: try: # keep the ticket for SLO session['cas_ticket'] = ticket return cortex.lib.user.logon_ok( cas_response.attributes.get('uid')) except KeyError: # required user attributes not returned flash( "CAS SSO authentication successful but missing required information consider using LDAP authentication", 'alert-warning') return root() return redirect(cas_client.get_login_url())
def test_perform_api_request(self): class MockResponse(object): text = '{"something": "useful"}' success = True cas_client = CASClient('https://dummy.url') url = self._get_test_api_url() service_ticket = 'ST-14600760351898-0B3lSFt2jOWSbgQ377B4CtbD9uq0MXR9kG23vAuH' assert not cas_client.headers with mock.patch('cas_client.CASClient._perform_post') as m: m.return_value = MockResponse() response = cas_client.perform_api_request( url, method='POST', body={'st': service_ticket}, timeout=45) m.assert_called_once_with(url, data={'st': service_ticket}, headers=None, timeout=45) print(response) self.assertTrue(response.success) self.assertEqual(json.loads(response.text), {'something': 'useful'})
def test_get_auth_token_login_url(self): cas_client = CASClient('https://dummy.url') auth_token_ticket = 'AT-1234' authenticator = 'my_company_ldap' username = '******' service_url = 'https://example.com' with open(self.private_key_filepath, 'r') as file_pointer: private_key = file_pointer.read() url = cas_client.get_auth_token_login_url( auth_token_ticket=auth_token_ticket, authenticator=authenticator, private_key=private_key, service_url=service_url, username=username, ) query_string = url.partition('?')[-1] query_parameters = { key: value[0] for key, value in parse_qs(query_string).items() } assert query_parameters == { 'at': ('eyJhdXRoZW50aWNhdG9yIjogIm15X2NvbXBhbnlfbGRhcCIsICJ0aWNrZXQi' 'OiAiQVQtMTIzNCIsICJ1c2VybmFtZSI6ICJteV91c2VyIn0='), 'ats': ('pZ3m58k8Xpd+TDlYb+VDV89TVGoPIAgsxDMNGtNLqzchg/EFy12NzVaUbVSz' '1PNZdQ/klMrfvxzehLlFp9QkyfFoUS5pgUo9XXjpowWe0E9eKX5hBJjpmvD+' 'PhSMRXFOPUOLRohRX45aPqJ4mjh2MNP0mzKrRfoRoUT/6mmrvLRJu150rtnS' 'A5E4n0V4BeJXWIFYqqu8B4CP3fbg18HMB5g36P61m6I67kDmBLfTlmtrwvM5' 'Vh3r9q9HFGn1NGmdMTcqGwAqfrww2XuBBemTpcfvSLNhTf/nZ21042BDt0+J' 'TLNsGBxNKS39NznyOcf2g5XtscdJXcDcKan/eJI7WHNtpmJPzhA4H5wTuAm7' 'X0WgAN7hxmTYy3E0241j6Q1DNDuxvgkSMS7CJhD3p0Fp0kHsdCslLuqjMoou' 'THSshfJU6lvE4dc1vh3fdzKiAcmvMQ2RT4ACNQVwVYiE9UWu23D16yz08sV2' '9kzlFTCTXT608tHMVCx1x7K959IxcRUFld314ooqJ5BgrK/2QqtZXS0w581f' '8P5qViQoOrQ5gRiPZ/bT6eF24RLuKN78VEkak2z0B1aZqpEcG3wQC4qHeUaM' 'TgrihbVi6eIv7N5k6srSyGCAQ/9k7o53ZKG8MzkqMJq53AoEXNj8HNQxgO0D' 'OtFwXLMrlrFpmqPS5OcO9NM='), 'service': 'https://example.com', }
def test_get_logout_url(self): cas_client = CASClient("dummy.url") service_url = "app.url" url = cas_client.get_logout_url(service_url=service_url) self.assertEqual(url, "dummy.url/cas/logout?service=app.url")
[sys.path.append(i) for i in ['.', '..', 'server']] from server.blacklab import search_blacklab #pylint: disable=wrong-import-position from server.db import get_db #pylint: disable=wrong-import-position from flask_caching import Cache app = Flask(__name__, static_folder='../build') CORS(app) app.debug = True cache = Cache(config={'CACHE_TYPE': 'simple'}) cache.init_app(app) # cas authentication URL cas_url = 'https://secure.its.yale.edu/cas' cas_client = CASClient(cas_url, auth_prefix='') app.secret_key = hashlib.new('ripemd160').hexdigest() use_cas_auth = False use_param_auth = False ## # API routes ## @app.route('/api/tree') def items(): '''Fetch tree data''' db = get_db() try: return jsonify(list(db.fragments.find({}, {'_id': 0})))
from cas_client import CASClient from flask import Flask, redirect, request, session, url_for import logging logging.basicConfig(level=logging.DEBUG, filename='/tmp/app.log') app = Flask(__name__) app.secret_key = '\rr8tIPn7' app_login_url = 'http://*****:*****@app.route('/login') def login(): ticket = request.args.get('ticket') if ticket: try: cas_response = cas_client.perform_service_validate( ticket=ticket, service_url=app_login_url, ) except:
def test_get_logout_url(self): cas_client = CASClient('https://dummy.url') service_url = 'https://app.url' url = cas_client.get_logout_url(service_url=service_url) self.assertEqual( url, 'https://dummy.url/cas/logout?service=https://app.url')