def test_successful_external_first_login_without_attributes(self, mock_service_validate, mock_get_user_from_cas_resp, mock_external_first_login_authenticate): service_url = 'http://localhost:5000/dashboard/' user, validated_credentials, cas_resp = generate_external_user_with_resp(service_url, user=False, release=False) mock_service_validate.return_value = cas_resp mock_get_user_from_cas_resp.return_value = (None, validated_credentials, 'external_first_login') ticket = fake.md5() cas.make_response_from_ticket(ticket, service_url) assert_equal(user, mock_external_first_login_authenticate.call_args[0][0])
def test_successful_external_first_login_without_attributes(self, mock_service_validate, mock_get_user_from_cas_resp, mock_external_first_login_authenticate): service_url = 'http://localhost:5000/dashboard/' user, validated_credentials, cas_resp = generate_external_user_with_resp(service_url, user=False, release=False) mock_service_validate.return_value = cas_resp mock_get_user_from_cas_resp.return_value = (None, validated_credentials, 'external_first_login') ticket = fake.md5() cas.make_response_from_ticket(ticket, service_url) assert_equal(user, mock_external_first_login_authenticate.call_args[0][0])
def before_request(): # TODO: Fix circular import from framework.auth.core import get_user from framework.auth import cas from website.util import time as util_time # Central Authentication Server Ticket Validation and Authentication ticket = request.args.get('ticket') if ticket: service_url = furl.furl(request.url) service_url.args.pop('ticket') # Attempt to authenticate wih CAS, and return a proper redirect response return cas.make_response_from_ticket(ticket=ticket, service_url=service_url.url) if request.authorization: user = get_user(email=request.authorization.username, password=request.authorization.password) # Create an empty session # TODO: Shoudn't need to create a session for Basic Auth user_session = Session() set_session(user_session) if user: user_addon = user.get_addon('twofactor') if user_addon and user_addon.is_confirmed: otp = request.headers.get('X-OSF-OTP') if otp is None or not user_addon.verify_code(otp): # Must specify two-factor authentication OTP code or invalid two-factor authentication OTP code. user_session.data['auth_error_code'] = http.UNAUTHORIZED return user_session.data['auth_user_username'] = user.username user_session.data['auth_user_id'] = user._primary_key user_session.data['auth_user_fullname'] = user.fullname else: # Invalid key: Not found in database user_session.data['auth_error_code'] = http.UNAUTHORIZED return cookie = request.cookies.get(settings.COOKIE_NAME) if cookie: try: session_id = itsdangerous.Signer( settings.SECRET_KEY).unsign(cookie) user_session = Session.load(session_id) or Session(_id=session_id) except itsdangerous.BadData: return if not util_time.throttle_period_expired(user_session.date_created, settings.OSF_SESSION_TIMEOUT): if user_session.data.get( 'auth_user_id') and 'api' not in request.url: database['user'].update( {'_id': user_session.data.get('auth_user_id')}, {'$set': { 'date_last_login': datetime.utcnow() }}, w=0) set_session(user_session) else: remove_session(user_session)
def before_request(): from framework.auth import cas # Central Authentication Server Ticket Validation and Authentication ticket = request.args.get('ticket') if ticket: service_url = furl.furl(request.url) service_url.args.pop('ticket') # Attempt autn wih CAS, and return a proper redirect response resp = cas.make_response_from_ticket(ticket=ticket, service_url=service_url.url) if request.cookies.get(settings.COOKIE_NAME): # TODO: Delete legacy cookie, this special case can be removed anytime after 1/1/2016. # A cookie is received which could potentially be a legacy (pre multi-domain) cookie. # Issuing a targeted delete of the legacy cookie ensures the user does not end up in a # login loop whereby both cookies are sent to the server and one of them at random # read for authentication. resp.delete_cookie(settings.COOKIE_NAME, domain=None) return resp if request.authorization: # TODO: Fix circular import from framework.auth.core import get_user user = get_user( email=request.authorization.username, password=request.authorization.password ) # Create empty session # TODO: Shoudn't need to create a session for Basic Auth session = Session() set_session(session) if user: user_addon = user.get_addon('twofactor') if user_addon and user_addon.is_confirmed: otp = request.headers.get('X-OSF-OTP') if otp is None or not user_addon.verify_code(otp): # Must specify two-factor authentication OTP code or invalid two-factor # authentication OTP code. session.data['auth_error_code'] = http.UNAUTHORIZED return session.data['auth_user_username'] = user.username session.data['auth_user_id'] = user._primary_key session.data['auth_user_fullname'] = user.fullname else: # Invalid key: Not found in database session.data['auth_error_code'] = http.UNAUTHORIZED return cookie = request.cookies.get(settings.COOKIE_NAME) if cookie: try: session_id = itsdangerous.Signer(settings.SECRET_KEY).unsign(cookie) session = Session.load(session_id) or Session(_id=session_id) except itsdangerous.BadData: return if session.data.get('auth_user_id') and 'api' not in request.url: database['user'].update({'_id': session.data.get('auth_user_id')}, {'$set': {'date_last_login': datetime.utcnow()}}, w=0) set_session(session)
def before_request(): from framework.auth import authenticate from framework.auth.core import User from framework.auth import cas # Central Authentication Server Ticket Validation and Authentication ticket = request.args.get('ticket') if ticket: service_url = furl.furl(request.url) service_url.args.pop('ticket') # Attempt autn wih CAS, and return a proper redirect response return cas.make_response_from_ticket(ticket=ticket, service_url=service_url.url) # Central Authentication Server OAuth Bearer Token authorization = request.headers.get('Authorization') if authorization and authorization.startswith('Bearer '): client = cas.get_client() try: access_token = cas.parse_auth_header(authorization) except cas.CasTokenError as err: # NOTE: We assume that the request is an AJAX request return jsonify({'message_short': 'Invalid Bearer token', 'message_long': err.args[0]}), http.UNAUTHORIZED cas_resp = client.profile(access_token) if cas_resp.authenticated: user = User.load(cas_resp.user) return authenticate(user, access_token=access_token, response=None) return make_response('', http.UNAUTHORIZED) if request.authorization: # TODO: Fix circular import from framework.auth.core import get_user user = get_user( email=request.authorization.username, password=request.authorization.password ) # Create empty session # TODO: Shoudn't need to create a session for Basic Auth session = Session() if user: session.data['auth_user_username'] = user.username session.data['auth_user_id'] = user._primary_key session.data['auth_user_fullname'] = user.fullname else: # Invalid key: Not found in database session.data['auth_error_code'] = http.FORBIDDEN set_session(session) return cookie = request.cookies.get(settings.COOKIE_NAME) if cookie: try: session_id = itsdangerous.Signer(settings.SECRET_KEY).unsign(cookie) session = Session.load(session_id) or Session(_id=session_id) set_session(session) return except: pass
def test_make_response_from_ticket_no_user(self, mock_service_validate): mock_response = make_external_response() mock_service_validate.return_value = mock_response ticket = fake.md5() service_url = "http://accounts.osf.io/?ticket=" + ticket resp = cas.make_response_from_ticket(ticket, service_url) assert_equal(resp.status_code, 302) assert_equal(resp.location, "/external-login/email")
def test_make_response_from_ticket_failure(self, mock_service_validate): mock_response = make_failure_response() mock_service_validate.return_value = mock_response ticket = fake.md5() service_url = 'http://accounts.osf.io/?ticket=' + ticket resp = cas.make_response_from_ticket(ticket, service_url) assert_equal(resp.status_code, 302) assert_equal(resp.location, 'http://accounts.osf.io/')
def test_make_response_from_ticket_failure(self, mock_service_validate): mock_response = make_failure_response() mock_service_validate.return_value = mock_response ticket = fake.md5() service_url = 'http://accounts.osf.io/?ticket=' + ticket resp = cas.make_response_from_ticket(ticket, service_url) assert_equal(resp.status_code, 302) assert_equal(resp.location, 'http://accounts.osf.io/')
def test_make_response_from_ticket_invalidates_verification_key(self, mock_service_validate): self.user.verification_key = fake.md5() self.user.save() mock_response = make_successful_response(self.user) mock_service_validate.return_value = mock_response ticket = fake.md5() service_url = 'http://accounts.osf.io/?ticket=' + ticket resp = cas.make_response_from_ticket(ticket, service_url)
def test_make_response_from_ticket_invalidates_verification_key(self, mock_service_validate): self.user.verification_key = fake.md5() self.user.save() mock_service_validate.return_value = make_successful_response(self.user) ticket = fake.md5() service_url = 'http://localhost:5000/' resp = cas.make_response_from_ticket(ticket, service_url) assert_true(self.user.verification_key is None)
def test_make_response_from_ticket_invalidates_verification_key(self, mock_service_validate): self.user.verification_key = fake.md5() self.user.save() mock_response = make_successful_response(self.user) mock_service_validate.return_value = mock_response ticket = fake.md5() service_url = 'http://accounts.osf.io/?ticket=' + ticket resp = cas.make_response_from_ticket(ticket, service_url)
def test_make_response_from_ticket_success(self, mock_service_validate, mock_get_user_from_cas_resp): mock_service_validate.return_value = make_successful_response(self.user) mock_get_user_from_cas_resp.return_value = (self.user, None, 'authenticate') ticket = fake.md5() service_url = 'http://localhost:5000/' resp = cas.make_response_from_ticket(ticket, service_url) assert_equal(resp.status_code, 302) assert_equal(mock_service_validate.call_count, 1) assert_equal(mock_get_user_from_cas_resp.call_count, 1)
def test_make_response_from_ticket_failure(self, mock_service_validate, mock_get_user_from_cas_resp): mock_service_validate.return_value = make_failure_response() mock_get_user_from_cas_resp.return_value = (None, None, None) ticket = fake.md5() service_url = 'http://localhost:5000/' resp = cas.make_response_from_ticket(ticket, service_url) assert_equal(resp.status_code, 302) assert_equal(mock_service_validate.call_count, 1) assert_equal(mock_get_user_from_cas_resp.call_count, 0)
def test_make_response_from_ticket_invalidates_verification_key(self, mock_service_validate): self.user.verification_key = fake.md5() self.user.save() mock_service_validate.return_value = make_successful_response(self.user) ticket = fake.md5() service_url = 'http://localhost:5000/' resp = cas.make_response_from_ticket(ticket, service_url) self.user.reload() assert_true(self.user.verification_key is None)
def test_make_response_from_ticket_failure(self, mock_service_validate, mock_get_user_from_cas_resp): mock_service_validate.return_value = make_failure_response() mock_get_user_from_cas_resp.return_value = (None, None, None) ticket = fake.md5() service_url = 'http://localhost:5000/' resp = cas.make_response_from_ticket(ticket, service_url) assert_equal(resp.status_code, 302) assert_equal(mock_service_validate.call_count, 1) assert_equal(mock_get_user_from_cas_resp.call_count, 0)
def test_make_response_from_ticket_success(self, mock_service_validate, mock_get_user_from_cas_resp): mock_service_validate.return_value = make_successful_response(self.user) mock_get_user_from_cas_resp.return_value = (self.user, None, 'authenticate') ticket = fake.md5() service_url = 'http://localhost:5000/' resp = cas.make_response_from_ticket(ticket, service_url) assert_equal(resp.status_code, 302) assert_equal(mock_service_validate.call_count, 1) assert_equal(mock_get_user_from_cas_resp.call_count, 1)
def test_successful_external_first_login(self, mock_service_validate, mock_get_user_from_cas_resp): service_url = 'http://localhost:5000/dashboard/' _, validated_credentials, cas_resp = generate_external_user_with_resp(service_url, user=False) mock_service_validate.return_value = cas_resp mock_get_user_from_cas_resp.return_value = (None, validated_credentials, 'external_first_login') ticket = fake.md5() resp = cas.make_response_from_ticket(ticket, service_url) assert_equal(resp.status_code, 302, 'redirect to external login email get') assert_in('/external-login/email', resp.location)
def test_successful_external_first_login(self, mock_service_validate, mock_get_user_from_cas_resp): service_url = 'http://localhost:5000/dashboard/' _, validated_credentials, cas_resp = generate_external_user_with_resp(service_url, user=False) mock_service_validate.return_value = cas_resp mock_get_user_from_cas_resp.return_value = (None, validated_credentials, 'external_first_login') ticket = fake.md5() resp = cas.make_response_from_ticket(ticket, service_url) assert_equal(resp.status_code, 302, 'redirect to external login email get') assert_in('/external-login/email', resp.location)
def before_request(): from framework.auth import cas from website.util import time as util_time # Central Authentication Server Ticket Validation and Authentication ticket = request.args.get('ticket') if ticket: service_url = furl.furl(request.url) service_url.args.pop('ticket') # Attempt autn wih CAS, and return a proper redirect response return cas.make_response_from_ticket(ticket=ticket, service_url=service_url.url) if request.authorization: # TODO: Fix circular import from framework.auth.core import get_user user = get_user( email=request.authorization.username, password=request.authorization.password ) # Create empty session # TODO: Shoudn't need to create a session for Basic Auth session = Session() set_session(session) if user: user_addon = user.get_addon('twofactor') if user_addon and user_addon.is_confirmed: otp = request.headers.get('X-OSF-OTP') if otp is None or not user_addon.verify_code(otp): # Must specify two-factor authentication OTP code or invalid two-factor # authentication OTP code. session.data['auth_error_code'] = http.UNAUTHORIZED return session.data['auth_user_username'] = user.username session.data['auth_user_id'] = user._primary_key session.data['auth_user_fullname'] = user.fullname else: # Invalid key: Not found in database session.data['auth_error_code'] = http.UNAUTHORIZED return cookie = request.cookies.get(settings.COOKIE_NAME) if cookie: try: session_id = itsdangerous.Signer(settings.SECRET_KEY).unsign(cookie) session = Session.load(session_id) or Session(_id=session_id) except itsdangerous.BadData: return if not util_time.throttle_period_expired(session.date_created, settings.OSF_SESSION_TIMEOUT): if session.data.get('auth_user_id') and 'api' not in request.url: database['user'].update({'_id': session.data.get('auth_user_id')}, {'$set': {'date_last_login': datetime.utcnow()}}, w=0) set_session(session) else: remove_session(session)
def test_make_response_from_ticket_invalidates_verification_key(self, mock_service_validate): self.user.verification_key = fake.md5() self.user.save() mock_response = make_external_response() validated_creds = cas.validate_external_credential(mock_response.user) self.user.external_identity = {validated_creds["provider"]: {validated_creds["id"]: "VERIFIED"}} self.user.save() mock_service_validate.return_value = mock_response ticket = fake.md5() service_url = "http://accounts.osf.io/?ticket=" + ticket resp = cas.make_response_from_ticket(ticket, service_url)
def test_make_response_from_ticket_handles_unicode(self, mock_service_validate): mock_response = make_external_response(unicode=True) mock_service_validate.return_value = mock_response ticket = fake.md5() service_url = 'http://localhost:5000/' resp = cas.make_response_from_ticket(ticket, service_url) assert_equal(resp.status_code, 302) assert_equal(mock_service_validate.call_count, 1) first_call_args = mock_service_validate.call_args[0] assert_equal(first_call_args[0], ticket) assert_equal(first_call_args[1], 'http://localhost:5000/')
def test_make_response_from_ticket_handles_non_unicode(self, mock_service_validate): mock_response = make_external_response() mock_service_validate.return_value = mock_response ticket = fake.md5() service_url = "http://accounts.osf.io/?ticket=" + ticket resp = cas.make_response_from_ticket(ticket, service_url) assert_equal(resp.status_code, 302) assert_equal(mock_service_validate.call_count, 1) first_call_args = mock_service_validate.call_args[0] assert_equal(first_call_args[0], ticket) assert_equal(first_call_args[1], "http://accounts.osf.io/")
def test_successful_external_login_cas_redirect(self, mock_service_validate, mock_get_user_from_cas_resp): service_url = 'http://localhost:5000/dashboard/' user, validated_credentials, cas_resp = generate_external_user_with_resp(service_url) mock_service_validate.return_value = cas_resp mock_get_user_from_cas_resp.return_value = (user, validated_credentials, 'authenticate') ticket = fake.md5() resp = cas.make_response_from_ticket(ticket, service_url) assert_equal(resp.status_code, 302, 'redirect to CAS login') assert_in('/login?service=', resp.location) assert_in('username={}'.format(user.username), resp.location) assert_in('verification_key={}'.format(user.verification_key), resp.location)
def test_successful_external_login_cas_redirect(self, mock_service_validate, mock_get_user_from_cas_resp): user, validated_credentials, cas_resp = generate_external_user_with_resp() mock_service_validate.return_value = cas_resp mock_get_user_from_cas_resp.return_value = (user, validated_credentials, 'authenticate') ticket = fake.md5() service_url = 'http://accounts.osf.io/?ticket=' + ticket resp = cas.make_response_from_ticket(ticket, service_url) assert_equal(resp.status_code, 302, 'redirect to CAS login') assert_in('/login?service=', resp.location) assert_in('username={}'.format(user.username), resp.location) assert_in('verification_key={}'.format(user.verification_key), resp.location)
def test_make_response_from_ticket_success(self, mock_service_validate): mock_response = make_successful_response(self.user) mock_service_validate.return_value = mock_response ticket = fake.md5() service_url = 'http://accounts.osf.io/?ticket=' + ticket resp = cas.make_response_from_ticket(ticket, service_url) assert_equal(resp.status_code, 302) mock_service_validate.assert_called_once() first_call_args = mock_service_validate.call_args[0] assert_equal(first_call_args[0], ticket) assert_equal(first_call_args[1], 'http://accounts.osf.io/')
def test_make_response_from_ticket_handles_non_unicode(self, mock_service_validate): mock_response = make_external_response() mock_service_validate.return_value = mock_response ticket = fake.md5() service_url = 'http://localhost:5000/' resp = cas.make_response_from_ticket(ticket, service_url) assert_equal(resp.status_code, 302) assert_equal(mock_service_validate.call_count, 1) first_call_args = mock_service_validate.call_args[0] assert_equal(first_call_args[0], ticket) assert_equal(first_call_args[1], 'http://localhost:5000/')
def test_make_response_from_ticket_success(self, mock_service_validate): mock_response = make_successful_response(self.user) mock_service_validate.return_value = mock_response ticket = fake.md5() service_url = 'http://accounts.osf.io/?ticket=' + ticket resp = cas.make_response_from_ticket(ticket, service_url) assert_equal(resp.status_code, 302) mock_service_validate.assert_called_once() first_call_args = mock_service_validate.call_args[0] assert_equal(first_call_args[0], ticket) assert_equal(first_call_args[1], 'http://accounts.osf.io/')
def test_make_response_from_ticket_no_user(self, mock_service_validate, mock_get_user_from_cas_resp): mock_response = make_external_response() mock_service_validate.return_value = mock_response validated_creds = cas.validate_external_credential(mock_response.user) mock_get_user_from_cas_resp.return_value = (None, validated_creds, 'external_first_login') ticket = fake.md5() service_url = 'http://localhost:5000/' resp = cas.make_response_from_ticket(ticket, service_url) assert_equal(mock_service_validate.call_count, 1) assert_true(mock_get_user_from_cas_resp.call_count, 1) assert_equal(resp.status_code, 302) assert_equal(resp.location, '/external-login/email')
def test_make_response_from_ticket_no_user(self, mock_service_validate, mock_get_user_from_cas_resp): mock_response = make_external_response() mock_service_validate.return_value = mock_response validated_creds = cas.validate_external_credential(mock_response.user) mock_get_user_from_cas_resp.return_value = (None, validated_creds, 'external_first_login') ticket = fake.md5() service_url = 'http://localhost:5000/' resp = cas.make_response_from_ticket(ticket, service_url) assert_equal(mock_service_validate.call_count, 1) assert_true(mock_get_user_from_cas_resp.call_count, 1) assert_equal(resp.status_code, 302) assert_equal(resp.location, '/external-login/email')
def test_make_response_from_ticket_handles_unicode(self, mock_service_validate): mock_response = make_external_response(unicode=True) mock_service_validate.return_value = mock_response ticket = fake.md5() service_url = 'http://accounts.osf.io/?ticket=' + ticket resp = cas.make_response_from_ticket(ticket, service_url) assert_equal(resp.status_code, 302) assert_equal(mock_service_validate.call_count, 1) first_call_args = mock_service_validate.call_args[0] assert_equal(first_call_args[0], ticket) assert_equal(first_call_args[1], 'http://accounts.osf.io/')
def before_request(): from framework.auth import cas # Central Authentication Server Ticket Validation and Authentication ticket = request.args.get('ticket') if ticket: service_url = furl.furl(request.url) service_url.args.pop('ticket') # Attempt autn wih CAS, and return a proper redirect response resp = cas.make_response_from_ticket(ticket=ticket, service_url=service_url.url) if request.cookies.get(settings.COOKIE_NAME): # TODO: Delete legacy cookie, this special case can be removed anytime after 1/1/2016. # A cookie is received which could potentially be a legacy (pre multi-domain) cookie. # Issuing a targeted delete of the legacy cookie ensures the user does not end up in a # login loop whereby both cookies are sent to the server and one of them at random # read for authentication. resp.delete_cookie(settings.COOKIE_NAME, domain=None) return resp if request.authorization: # TODO: Fix circular import from framework.auth.core import get_user user = get_user( email=request.authorization.username, password=request.authorization.password ) # Create empty session # TODO: Shoudn't need to create a session for Basic Auth session = Session() if user: session.data['auth_user_username'] = user.username session.data['auth_user_id'] = user._primary_key session.data['auth_user_fullname'] = user.fullname user.date_last_login = datetime.utcnow() user.save() else: # Invalid key: Not found in database session.data['auth_error_code'] = http.FORBIDDEN set_session(session) return cookie = request.cookies.get(settings.COOKIE_NAME) if cookie: try: session_id = itsdangerous.Signer(settings.SECRET_KEY).unsign(cookie) session = Session.load(session_id) or Session(_id=session_id) except itsdangerous.BadData: return if session.data.get('auth_user_id'): database['user'].update({'_id': session.data.get('auth_user_id')}, {'$set': {'date_last_login': datetime.utcnow()}}, w=0) set_session(session)
def test_can_reset_password_if_form_success(self, mock_service_validate): # load reset password page and submit email res = self.app.get(self.get_url) form = res.forms['resetPasswordForm'] form['password'] = '******' form['password2'] = 'newpassword' res = form.submit() # check request URL is /resetpassword with username and new verification_key_v2 token request_url_path = res.request.path assert_in('resetpassword', request_url_path) assert_in(self.user._id, request_url_path) assert_not_in(self.user.verification_key_v2['token'], request_url_path) # check verification_key_v2 for OSF is destroyed and verification_key for CAS is in place self.user.reload() assert_equal(self.user.verification_key_v2, {}) assert_not_equal(self.user.verification_key, None) # check redirection to CAS login with username and the new verification_key(CAS) assert_equal(res.status_code, 302) location = res.headers.get('Location') assert_true('login?service=' in location) assert_true('username={}'.format(self.user.username) in location) assert_true('verification_key={}'.format(self.user.verification_key) in location) # check if password was updated self.user.reload() assert_true(self.user.check_password('newpassword')) # check if verification_key is destroyed after service validation mock_service_validate.return_value = cas.CasResponse( authenticated=True, user=self.user._primary_key, attributes={'accessToken': fake.md5()}) ticket = fake.md5() service_url = 'http://accounts.osf.io/?ticket=' + ticket cas.make_response_from_ticket(ticket, service_url) assert_equal(self.user.verification_key, None)
def test_can_reset_password_if_form_success(self, mock_service_validate): # load reset password page and submit email res = self.app.get(self.get_url) form = res.forms['resetPasswordForm'] form['password'] = '******' form['password2'] = 'newpassword' res = form.submit() # check request URL is /resetpassword with username and new verification_key_v2 token request_url_path = res.request.path assert_in('resetpassword', request_url_path) assert_in(self.user._id, request_url_path) assert_not_in(self.user.verification_key_v2['token'], request_url_path) # check verification_key_v2 for OSF is destroyed and verification_key for CAS is in place self.user.reload() assert_equal(self.user.verification_key_v2, {}) assert_not_equal(self.user.verification_key, None) # check redirection to CAS login with username and the new verification_key(CAS) assert_equal(res.status_code, 302) location = res.headers.get('Location') assert_true('login?service=' in location) assert_true('username={}'.format(self.user.username) in location) assert_true('verification_key={}'.format(self.user.verification_key) in location) # check if password was updated self.user.reload() assert_true(self.user.check_password('newpassword')) # check if verification_key is destroyed after service validation mock_service_validate.return_value = cas.CasResponse( authenticated=True, user=self.user._primary_key, attributes={'accessToken': fake.md5()} ) ticket = fake.md5() service_url = 'http://accounts.osf.io/?ticket=' + ticket cas.make_response_from_ticket(ticket, service_url) assert_equal(self.user.verification_key, None)
def test_successful_external_login_cas_redirect(self, mock_service_validate, mock_get_user_from_cas_resp): service_url = 'http://*****:*****@'), safe='@') assert_in('username={}'.format(username_quoted), resp.location) assert_in('verification_key={}'.format(user.verification_key), resp.location)
def test_make_response_from_ticket_with_user(self, mock_service_validate): mock_response = make_external_response() mock_service_validate.return_value = mock_response validated_creds = cas.validate_external_credential(mock_response.user) self.user.external_identity = {validated_creds["provider"]: {validated_creds["id"]: "VERIFIED"}} self.user.save() ticket = fake.md5() service_url = "http://accounts.osf.io/?ticket=" + ticket resp = cas.make_response_from_ticket(ticket, service_url) assert_equal(resp.status_code, 302) assert_equal(mock_service_validate.call_count, 1) first_call_args = mock_service_validate.call_args[0] assert_equal(first_call_args[0], ticket) assert_equal(first_call_args[1], "http://accounts.osf.io/")
def test_successful_external_login_cas_redirect(self, mock_service_validate, mock_get_user_from_cas_resp): service_url = 'http://*****:*****@'), safe='@') assert_in('username={}'.format(username_quoted), resp.location) assert_in('verification_key={}'.format(user.verification_key), resp.location)
def before_request(): from framework.auth import cas # Central Authentication Server Ticket Validation and Authentication ticket = request.args.get('ticket') if ticket: service_url = furl.furl(request.url) service_url.args.pop('ticket') # Attempt autn wih CAS, and return a proper redirect response resp = cas.make_response_from_ticket(ticket=ticket, service_url=service_url.url) if request.cookies.get(settings.COOKIE_NAME): # TODO: Delete legacy cookie, this special case can be removed anytime after 1/1/2016. # A cookie is received which could potentially be a legacy (pre multi-domain) cookie. # Issuing a targeted delete of the legacy cookie ensures the user does not end up in a # login loop whereby both cookies are sent to the server and one of them at random # read for authentication. resp.delete_cookie(settings.COOKIE_NAME, domain=None) return resp if request.authorization: # TODO: Fix circular import from framework.auth.core import get_user user = get_user( email=request.authorization.username, password=request.authorization.password ) # Create empty session # TODO: Shoudn't need to create a session for Basic Auth session = Session() if user: session.data['auth_user_username'] = user.username session.data['auth_user_id'] = user._primary_key session.data['auth_user_fullname'] = user.fullname else: # Invalid key: Not found in database session.data['auth_error_code'] = http.FORBIDDEN set_session(session) return cookie = request.cookies.get(settings.COOKIE_NAME) if cookie: try: session_id = itsdangerous.Signer(settings.SECRET_KEY).unsign(cookie) session = Session.load(session_id) or Session(_id=session_id) set_session(session) return except: pass
def test_make_response_from_ticket_invalidates_verification_key(self, mock_service_validate): self.user.verification_key = fake.md5() self.user.save() mock_response = make_external_response() validated_creds = cas.validate_external_credential(mock_response.user) self.user.external_identity = { validated_creds['provider']: { validated_creds['id']: 'VERIFIED' } } self.user.save() mock_service_validate.return_value = mock_response ticket = fake.md5() service_url = 'http://accounts.osf.io/?ticket=' + ticket resp = cas.make_response_from_ticket(ticket, service_url)
def test_make_response_from_ticket_generates_new_verification_key(self, mock_service_validate): self.user.verification_key = fake.md5() self.user.save() mock_response = make_external_response() validated_creds = cas.validate_external_credential(mock_response.user) self.user.external_identity = { validated_creds['provider']: { validated_creds['id']: 'VERIFIED' } } self.user.save() mock_service_validate.return_value = mock_response ticket = fake.md5() service_url = 'http://localhost:5000/' verification_key = self.user.verification_key resp = cas.make_response_from_ticket(ticket, service_url) assert_not_equal(self.user.verification_key, verification_key)
def test_make_response_from_ticket_with_user(self, mock_service_validate): mock_response = make_external_response() mock_service_validate.return_value = mock_response validated_creds = cas.validate_external_credential(mock_response.user) self.user.external_identity = { validated_creds['provider']: { validated_creds['id']: 'VERIFIED' } } self.user.save() ticket = fake.md5() service_url = 'http://accounts.osf.io/?ticket=' + ticket resp = cas.make_response_from_ticket(ticket, service_url) assert_equal(resp.status_code, 302) assert_equal(mock_service_validate.call_count, 1) first_call_args = mock_service_validate.call_args[0] assert_equal(first_call_args[0], ticket) assert_equal(first_call_args[1], 'http://accounts.osf.io/')
def test_make_response_from_ticket_generates_new_verification_key(self, mock_service_validate): self.user.verification_key = fake.md5() self.user.save() mock_response = make_external_response() validated_creds = cas.validate_external_credential(mock_response.user) self.user.external_identity = { validated_creds['provider']: { validated_creds['id']: 'VERIFIED' } } self.user.save() mock_service_validate.return_value = mock_response ticket = fake.md5() service_url = 'http://localhost:5000/' verification_key = self.user.verification_key resp = cas.make_response_from_ticket(ticket, service_url) self.user.reload() assert_not_equal(self.user.verification_key, verification_key)
def test_make_response_from_ticket_with_user(self, mock_service_validate, mock_get_user_from_cas_resp): mock_response = make_external_response() mock_service_validate.return_value = mock_response validated_creds = cas.validate_external_credential(mock_response.user) self.user.external_identity = { validated_creds['provider']: { validated_creds['id']: 'VERIFIED' } } self.user.save() mock_get_user_from_cas_resp.return_value = (self.user, validated_creds, 'authenticate') ticket = fake.md5() service_url = 'http://localhost:5000/' resp = cas.make_response_from_ticket(ticket, service_url) assert_equal(mock_service_validate.call_count, 1) assert_true(mock_get_user_from_cas_resp.call_count, 1) assert_equal(resp.status_code, 302) assert_in('/logout?service=', resp.headers['Location']) assert_in('/login?service=', resp.headers['Location'])
def test_make_response_from_ticket_with_user(self, mock_service_validate, mock_get_user_from_cas_resp): mock_response = make_external_response() mock_service_validate.return_value = mock_response validated_creds = cas.validate_external_credential(mock_response.user) self.user.external_identity = { validated_creds['provider']: { validated_creds['id']: 'VERIFIED' } } self.user.save() mock_get_user_from_cas_resp.return_value = (self.user, validated_creds, 'authenticate') ticket = fake.md5() service_url = 'http://localhost:5000/' resp = cas.make_response_from_ticket(ticket, service_url) assert_equal(mock_service_validate.call_count, 1) assert_true(mock_get_user_from_cas_resp.call_count, 1) assert_equal(resp.status_code, 302) assert_in('/logout?service=', resp.headers['Location']) assert_in('/login?service=', resp.headers['Location'])
def before_request(): from framework.auth import cas # Central Authentication Server Ticket Validation and Authentication ticket = request.args.get('ticket') if ticket: service_url = furl.furl(request.url) service_url.args.pop('ticket') # Attempt autn wih CAS, and return a proper redirect response return cas.make_response_from_ticket(ticket=ticket, service_url=service_url.url) if request.authorization: # TODO: Fix circular import from framework.auth.core import get_user user = get_user( email=request.authorization.username, password=request.authorization.password ) # Create empty session # TODO: Shoudn't need to create a session for Basic Auth session = Session() if user: session.data['auth_user_username'] = user.username session.data['auth_user_id'] = user._primary_key session.data['auth_user_fullname'] = user.fullname else: # Invalid key: Not found in database session.data['auth_error_code'] = http.FORBIDDEN set_session(session) return cookie = request.cookies.get(settings.COOKIE_NAME) if cookie: try: session_id = itsdangerous.Signer(settings.SECRET_KEY).unsign(cookie) session = Session.load(session_id) or Session(_id=session_id) set_session(session) return except: pass
def before_request(): from framework.auth import cas # Central Authentication Server Ticket Validation and Authentication ticket = request.args.get('ticket') if ticket: service_url = furl.furl(request.url) service_url.args.pop('ticket') # Attempt autn wih CAS, and return a proper redirect response return cas.make_response_from_ticket(ticket=ticket, service_url=service_url.url) if request.authorization: # TODO: Fix circular import from framework.auth.core import get_user user = get_user(email=request.authorization.username, password=request.authorization.password) # Create empty session # TODO: Shoudn't need to create a session for Basic Auth session = Session() if user: session.data['auth_user_username'] = user.username session.data['auth_user_id'] = user._primary_key session.data['auth_user_fullname'] = user.fullname else: # Invalid key: Not found in database session.data['auth_error_code'] = http.FORBIDDEN set_session(session) return cookie = request.cookies.get(settings.COOKIE_NAME) if cookie: try: session_id = itsdangerous.Signer( settings.SECRET_KEY).unsign(cookie) session = Session.load(session_id) or Session(_id=session_id) set_session(session) return except: pass
def before_request(): from framework import sentry from framework.auth import cas from framework.auth.core import User from framework.auth import authenticate from framework.routing import json_renderer # Central Authentication Server Ticket Validation and Authentication ticket = request.args.get('ticket') if ticket: service_url = furl.furl(request.url) service_url.args.pop('ticket') # Attempt autn wih CAS, and return a proper redirect response return cas.make_response_from_ticket(ticket=ticket, service_url=service_url.url) # Central Authentication Server OAuth Bearer Token authorization = request.headers.get('Authorization') if authorization and authorization.startswith('Bearer '): client = cas.get_client() try: access_token = cas.parse_auth_header(authorization) cas_resp = client.profile(access_token) except cas.CasError as err: sentry.log_exception() # NOTE: We assume that the request is an AJAX request return json_renderer(err) if cas_resp.authenticated: user = User.load(cas_resp.user) return authenticate(user, access_token=access_token, response=None) return make_response('', http.UNAUTHORIZED) if request.authorization: # TODO: Fix circular import from framework.auth.core import get_user user = get_user(email=request.authorization.username, password=request.authorization.password) # Create empty session # TODO: Shoudn't need to create a session for Basic Auth session = Session() if user: session.data['auth_user_username'] = user.username session.data['auth_user_id'] = user._primary_key session.data['auth_user_fullname'] = user.fullname else: # Invalid key: Not found in database session.data['auth_error_code'] = http.FORBIDDEN set_session(session) return cookie = request.cookies.get(settings.COOKIE_NAME) if cookie: try: session_id = itsdangerous.Signer( settings.SECRET_KEY).unsign(cookie) session = Session.load(session_id) or Session(_id=session_id) set_session(session) return except: pass
def before_request(): # TODO: Fix circular import from framework.auth.core import get_user from framework.auth import cas from website.util import time as util_time Session = apps.get_model('osf.Session') # Central Authentication Server Ticket Validation and Authentication ticket = request.args.get('ticket') if ticket: service_url = furl.furl(request.url) service_url.args.pop('ticket') # Attempt to authenticate wih CAS, and return a proper redirect response return cas.make_response_from_ticket(ticket=ticket, service_url=service_url.url) if request.authorization: user = get_user( email=request.authorization.username, password=request.authorization.password ) # Create an empty session # TODO: Shoudn't need to create a session for Basic Auth user_session = Session() set_session(user_session) if user: user_addon = user.get_addon('twofactor') if user_addon and user_addon.is_confirmed: otp = request.headers.get('X-OSF-OTP') if otp is None or not user_addon.verify_code(otp): # Must specify two-factor authentication OTP code or invalid two-factor authentication OTP code. user_session.data['auth_error_code'] = http.UNAUTHORIZED return user_session.data['auth_user_username'] = user.username user_session.data['auth_user_fullname'] = user.fullname if user_session.data.get('auth_user_id', None) != user._primary_key: user_session.data['auth_user_id'] = user._primary_key user_session.save() else: # Invalid key: Not found in database user_session.data['auth_error_code'] = http.UNAUTHORIZED return cookie = request.cookies.get(settings.COOKIE_NAME) if cookie: try: session_id = itsdangerous.Signer(settings.SECRET_KEY).unsign(cookie) user_session = Session.load(session_id) or Session(_id=session_id) except itsdangerous.BadData: return if not util_time.throttle_period_expired(user_session.created, settings.OSF_SESSION_TIMEOUT): # Update date last login when making non-api requests if user_session.data.get('auth_user_id') and 'api' not in request.url: OSFUser = apps.get_model('osf.OSFUser') ( OSFUser.objects .filter(guids___id__isnull=False, guids___id=user_session.data['auth_user_id']) # Throttle updates .filter(Q(date_last_login__isnull=True) | Q(date_last_login__lt=timezone.now() - dt.timedelta(seconds=settings.DATE_LAST_LOGIN_THROTTLE))) ).update(date_last_login=timezone.now()) set_session(user_session) else: remove_session(user_session)
def before_request(): from framework.auth import authenticate from framework.auth.core import User from framework.auth import cas # Central Authentication Server Ticket Validation and Authentication ticket = request.args.get('ticket') if ticket: service_url = furl.furl(request.url) service_url.args.pop('ticket') # Attempt autn wih CAS, and return a proper redirect response return cas.make_response_from_ticket(ticket=ticket, service_url=service_url.url) # Central Authentication Server OAuth Bearer Token authorization = request.headers.get('Authorization') if authorization and authorization.startswith('Bearer '): client = cas.get_client() try: access_token = cas.parse_auth_header(authorization) except cas.CasTokenError as err: # NOTE: We assume that the request is an AJAX request return jsonify({ 'message_short': 'Invalid Bearer token', 'message_long': err.args[0] }), http.UNAUTHORIZED cas_resp = client.profile(access_token) if cas_resp.authenticated: user = User.load(cas_resp.user) return authenticate(user, access_token=access_token, response=None) return make_response('', http.UNAUTHORIZED) if request.authorization: # Create a session from the API key; if key is # not valid, save the HTTP error code in the # "auth_error_code" field of session.data # Create empty session session = Session() # Hack: Avoid circular import from website.project.model import ApiKey api_label = request.authorization.username api_key_id = request.authorization.password api_key = ApiKey.load(api_key_id) if api_key: user = api_key.user__keyed and api_key.user__keyed[0] node = api_key.node__keyed and api_key.node__keyed[0] session.data['auth_api_label'] = api_label session.data['auth_api_key'] = api_key._primary_key if user: session.data['auth_user_username'] = user.username session.data['auth_user_id'] = user._primary_key session.data['auth_user_fullname'] = user.fullname elif node: session.data['auth_node_id'] = node._primary_key else: # Invalid key: Not attached to user or node session.data['auth_error_code'] = http.FORBIDDEN else: # Invalid key: Not found in database session.data['auth_error_code'] = http.FORBIDDEN set_session(session) return cookie = request.cookies.get(settings.COOKIE_NAME) if cookie: try: session_id = itsdangerous.Signer( settings.SECRET_KEY).unsign(cookie) session = Session.load(session_id) or Session(_id=session_id) set_session(session) return except: pass ## TODO: Create session in before_request, cookie in after_request ## Retry request, preserving status code #response = redirect(request.path, code=307) return create_session(None)
def before_request(): # TODO: Fix circular import from framework.auth.core import get_user from framework.auth import cas from framework.utils import throttle_period_expired Session = apps.get_model('osf.Session') # Central Authentication Server Ticket Validation and Authentication ticket = request.args.get('ticket') if ticket: service_url = furl.furl(request.url) service_url.args.pop('ticket') # Attempt to authenticate wih CAS, and return a proper redirect response return cas.make_response_from_ticket(ticket=ticket, service_url=service_url.url) if request.authorization: user = get_user(email=request.authorization.username, password=request.authorization.password) # Create an empty session # TODO: Shoudn't need to create a session for Basic Auth user_session = Session() set_session(user_session) if user: user_addon = user.get_addon('twofactor') if user_addon and user_addon.is_confirmed: otp = request.headers.get('X-OSF-OTP') if otp is None or not user_addon.verify_code(otp): # Must specify two-factor authentication OTP code or invalid two-factor authentication OTP code. user_session.data[ 'auth_error_code'] = http_status.HTTP_401_UNAUTHORIZED return user_session.data['auth_user_username'] = user.username user_session.data['auth_user_fullname'] = user.fullname if user_session.data.get('auth_user_id', None) != user._primary_key: user_session.data['auth_user_id'] = user._primary_key user_session.save() else: # Invalid key: Not found in database user_session.data[ 'auth_error_code'] = http_status.HTTP_401_UNAUTHORIZED return cookie = request.cookies.get(settings.COOKIE_NAME) if cookie: try: session_id = itsdangerous.Signer( settings.SECRET_KEY).unsign(cookie) user_session = Session.load(session_id) or Session(_id=session_id) except itsdangerous.BadData: return if not throttle_period_expired(user_session.created, settings.OSF_SESSION_TIMEOUT): # Update date last login when making non-api requests if user_session.data.get( 'auth_user_id') and 'api' not in request.url: OSFUser = apps.get_model('osf.OSFUser') (OSFUser.objects.filter( guids___id__isnull=False, guids___id=user_session.data['auth_user_id']) # Throttle updates .filter( Q(date_last_login__isnull=True) | Q(date_last_login__lt=timezone.now() - dt.timedelta( seconds=settings.DATE_LAST_LOGIN_THROTTLE)))).update( date_last_login=timezone.now()) set_session(user_session) else: remove_session(user_session)
def before_request(): from framework.auth import authenticate from framework.auth.core import User from framework.auth import cas # Central Authentication Server Ticket Validation and Authentication ticket = request.args.get('ticket') if ticket: service_url = furl.furl(request.url) service_url.args.pop('ticket') # Attempt autn wih CAS, and return a proper redirect response return cas.make_response_from_ticket(ticket=ticket, service_url=service_url.url) # Central Authentication Server OAuth Bearer Token authorization = request.headers.get('Authorization') if authorization and authorization.startswith('Bearer '): client = cas.get_client() try: access_token = cas.parse_auth_header(authorization) except cas.CasTokenError as err: # NOTE: We assume that the request is an AJAX request return jsonify({'message_short': 'Invalid Bearer token', 'message_long': err.args[0]}), http.UNAUTHORIZED cas_resp = client.profile(access_token) if cas_resp.authenticated: user = User.load(cas_resp.user) return authenticate(user, access_token=access_token, response=None) return make_response('', http.UNAUTHORIZED) if request.authorization: # Create a session from the API key; if key is # not valid, save the HTTP error code in the # "auth_error_code" field of session.data # Create empty session session = Session() # Hack: Avoid circular import from website.project.model import ApiKey api_label = request.authorization.username api_key_id = request.authorization.password api_key = ApiKey.load(api_key_id) if api_key: user = api_key.user__keyed and api_key.user__keyed[0] node = api_key.node__keyed and api_key.node__keyed[0] session.data['auth_api_label'] = api_label session.data['auth_api_key'] = api_key._primary_key if user: session.data['auth_user_username'] = user.username session.data['auth_user_id'] = user._primary_key session.data['auth_user_fullname'] = user.fullname elif node: session.data['auth_node_id'] = node._primary_key else: # Invalid key: Not attached to user or node session.data['auth_error_code'] = http.FORBIDDEN else: # Invalid key: Not found in database session.data['auth_error_code'] = http.FORBIDDEN set_session(session) return cookie = request.cookies.get(settings.COOKIE_NAME) if cookie: try: session_id = itsdangerous.Signer(settings.SECRET_KEY).unsign(cookie) session = Session.load(session_id) or Session(_id=session_id) set_session(session) return except: pass ## TODO: Create session in before_request, cookie in after_request ## Retry request, preserving status code #response = redirect(request.path, code=307) return create_session(None)