def twitter_process(request): """Process the Twitter redirect""" if 'denied' in request.GET: return AuthenticationDenied("User denied authentication") settings = request.registry.settings request_token = oauth.Token.from_string(request.session['token']) verifier = request.GET.get('oauth_verifier') if not verifier: raise ThirdPartyFailure("Oauth verifier not returned") request_token.set_verifier(verifier) # Create the consumer and client, make the request consumer = oauth.Consumer(settings['velruse.twitter.consumer_key'], settings['velruse.twitter.consumer_secret']) client = oauth.Client(consumer, request_token) resp, content = client.request(ACCESS_URL, "POST") if resp['status'] != '200': raise ThirdPartyFailure("Status %s: %s" % (resp['status'], content)) access_token = dict(parse_qs(content)) # Setup the normalized contact info profile = {} profile['accounts'] = [{ 'domain': 'twitter.com', 'userid': access_token['user_id'][0] }] profile['displayName'] = access_token['screen_name'][0] cred = { 'oauthAccessToken': access_token['oauth_token'][0], 'oauthAccessTokenSecret': access_token['oauth_token_secret'][0] } return TwitterAuthenticationComplete(profile=profile, credentials=cred)
def facebook_process(request): """Process the facebook redirect""" if request.GET.get('state') != request.session.get('state'): raise CSRFError( "CSRF Validation check failed. Request state %s is " "not the same as session state %s" % (request.GET.get('state'), request.session.get('state'))) config = request.registry.settings code = request.GET.get('code') if not code: reason = request.GET.get('error_reason', 'No reason provided.') return AuthenticationDenied(reason) # Now retrieve the access token with the code access_url = flat_url('https://graph.facebook.com/oauth/access_token', client_id=config['velruse.facebook.app_id'], client_secret=config['velruse.facebook.app_secret'], redirect_uri=request.route_url('facebook_process'), code=code) r = requests.get(access_url) if r.status_code != 200: raise ThirdPartyFailure("Status %s: %s" % (r.status_code, r.content)) access_token = parse_qs(r.content)['access_token'][0] # Retrieve profile data graph_url = flat_url('https://graph.facebook.com/me', access_token=access_token) r = requests.get(graph_url) if r.status_code != 200: raise ThirdPartyFailure("Status %s: %s" % (r.status_code, r.content)) fb_profile = loads(r.content) profile = extract_fb_data(fb_profile) cred = {'oauthAccessToken': access_token} return FacebookAuthenticationComplete(profile=profile, credentials=cred)
def callback(self, request): """Process the weibo redirect""" sess_state = request.session.get('state') req_state = request.GET.get('state') if not sess_state or sess_state != req_state: raise CSRFError( 'CSRF Validation check failed. Request state {req_state} is not ' 'the same as session state {sess_state}'.format( req_state=req_state, sess_state=sess_state)) code = request.GET.get('code') if not code: reason = request.GET.get('error_reason', 'No reason provided.') return AuthenticationDenied(reason, provider_name=self.name, provider_type=self.type) # Now retrieve the access token with the code r = requests.post( 'https://api.weibo.com/oauth2/access_token', dict( client_id=self.consumer_key, client_secret=self.consumer_secret, redirect_uri=request.route_url(self.callback_route), grant_type='authorization_code', code=code, ), ) if r.status_code != 200: raise ThirdPartyFailure("Status %s: %s" % (r.status_code, r.content)) data = loads(r.content) access_token = data['access_token'] uid = data['uid'] # Retrieve profile data graph_url = flat_url('https://api.weibo.com/2/users/show.json', access_token=access_token, uid=uid) r = requests.get(graph_url) if r.status_code != 200: raise ThirdPartyFailure("Status %s: %s" % (r.status_code, r.content)) data = loads(r.content) profile = { 'accounts': [{ 'domain': 'weibo.com', 'userid': data['id'] }], 'gender': data.get('gender'), 'displayName': data['screen_name'], 'preferredUsername': data['name'], } cred = {'oauthAccessToken': access_token} return WeiboAuthenticationComplete(profile=profile, credentials=cred, provider_name=self.name, provider_type=self.type)
def callback(self, request): """Process the github redirect""" sess_state = request.session.get('state') req_state = request.GET.get('state') if not sess_state or sess_state != req_state: raise CSRFError( 'CSRF Validation check failed. Request state {req_state} is not ' 'the same as session state {sess_state}'.format( req_state=req_state, sess_state=sess_state)) code = request.GET.get('code') if not code: reason = request.GET.get('error', 'No reason provided.') return AuthenticationDenied(reason=reason, provider_name=self.name, provider_type=self.type) # Now retrieve the access token with the code access_url = flat_url( '%s://%s/login/oauth/access_token' % (self.protocol, self.domain), client_id=self.consumer_key, client_secret=self.consumer_secret, redirect_uri=request.route_url(self.callback_route), code=code) r = requests.get(access_url) if r.status_code != 200: raise ThirdPartyFailure("Status %s: %s" % (r.status_code, r.content)) access_token = parse_qs(r.content)['access_token'][0] # Retrieve profile data graph_url = flat_url('%s://api.%s/user' % (self.protocol, self.domain), access_token=access_token) graph_headers = dict(Accept='application/vnd.github.v3+json') r = requests.get(graph_url, headers=graph_headers) if r.status_code != 200: raise ThirdPartyFailure("Status %s: %s" % (r.status_code, r.content)) data = loads(r.content) profile = {} profile['accounts'] = [{ 'domain': self.domain, 'username': data['login'], 'userid': data['id'] }] profile['preferredUsername'] = data['login'] profile['displayName'] = data.get('name', profile['preferredUsername']) # We don't add this to verifiedEmail because ppl can change email # addresses without verifying them if 'email' in data: profile['emails'] = [{'value': data['email']}] cred = {'oauthAccessToken': access_token} return GithubAuthenticationComplete(profile=profile, credentials=cred, provider_name=self.name, provider_type=self.type)
def callback(self, request): """Process the LinkedIn redirect""" if 'denied' in request.GET: return AuthenticationDenied("User denied authentication", provider_name=self.name, provider_type=self.type) request_token = oauth.Token.from_string(request.session['token']) verifier = request.GET.get('oauth_verifier') if not verifier: raise ThirdPartyFailure("Oauth verifier not returned") request_token.set_verifier(verifier) # Create the consumer and client, make the request consumer = oauth.Consumer(self.consumer_key, self.consumer_secret) client = oauth.Client(consumer, request_token) resp, content = client.request(ACCESS_URL, "POST") if resp['status'] != '200': raise ThirdPartyFailure("Status %s: %s" % (resp['status'], content)) access_token = dict(parse_qs(content)) cred = { 'oauthAccessToken': access_token['oauth_token'][0], 'oauthAccessTokenSecret': access_token['oauth_token_secret'][0] } # Make a request with the data for more user info token = oauth.Token(key=cred['oauthAccessToken'], secret=cred['oauthAccessTokenSecret']) client = oauth.Client(consumer, token) profile_url = 'http://api.linkedin.com/v1/people/~' profile_url += ':(first-name,last-name,id,date-of-birth,picture-url)' profile_url += '?format=json' resp, content = client.request(profile_url) if resp['status'] != '200': raise ThirdPartyFailure("Status %s: %s" % (resp['status'], content)) data = loads(content) # Setup the normalized contact info profile = {} profile['displayName'] = data['firstName'] + data['lastName'] profile['name'] = { 'givenName': data['firstName'], 'familyName': data['lastName'], 'formatted': '%s %s' % (data['firstName'], data['lastName']) } profile['accounts'] = [{ 'domain': 'linkedin.com', 'userid': data['id'] }] return LinkedInAuthenticationComplete(profile=profile, credentials=cred, provider_name=self.name, provider_type=self.type)
def callback(self, request): """Process the taobao redirect""" code = request.GET.get('code') if not code: reason = request.GET.get('error', 'No reason provided.') return AuthenticationDenied(reason) # Now retrieve the access token with the code r = requests.post( 'https://oauth.taobao.com/token', dict(grant_type='authorization_code', client_id=self.consumer_key, client_secret=self.consumer_secret, redirect_uri=request.route_url(self.callback_route), code=code)) if r.status_code != 200: raise ThirdPartyFailure("Status %s: %s" % (r.status_code, r.content)) data = loads(r.content) access_token = data['access_token'] # Retrieve profile data params = { 'method': 'taobao.user.get', 'timestamp': time.strftime('%Y-%m-%d %H:%M:%S', time.localtime()), 'format': 'json', 'app_key': self.consumer_key, 'v': '2.0', 'sign_method': 'md5', 'fields': 'user_id,nick', 'session': access_token } src = self.consumer_secret\ + ''.join(["%s%s" % (k, v) for k, v in sorted(params.items())])\ + self.consumer_secret params['sign'] = md5(src).hexdigest().upper() get_user_info_url = flat_url('http://gw.api.taobao.com/router/rest', **params) r = requests.get(get_user_info_url) if r.status_code != 200: raise ThirdPartyFailure("Status %s: %s" % (r.status_code, r.content)) data = loads(r.content) username = data['user_get_response']['user']['nick'] userid = data['user_get_response']['user']['user_id'] profile = { 'accounts': [{ 'domain': 'taobao.com', 'userid': userid }], 'displayName': username, 'preferredUsername': username, } cred = {'oauthAccessToken': access_token} return TaobaoAuthenticationComplete(profile=profile, credentials=cred)
def callback(self, request): """Process the qq redirect""" code = request.GET.get('code') if not code: reason = request.GET.get('error', 'No reason provided.') return AuthenticationDenied(reason, provider_name=self.name, provider_type=self.type) # Now retrieve the access token with the code access_url = flat_url('https://graph.qq.com/oauth2.0/token', client_id=self.consumer_key, client_secret=self.consumer_secret, grant_type='authorization_code', redirect_uri=request.route_url( self.callback_route), code=code) r = requests.get(access_url) if r.status_code != 200: raise ThirdPartyFailure("Status %s: %s" % (r.status_code, r.content)) access_token = parse_qs(r.content)['access_token'][0] # Retrieve profile data graph_url = flat_url('https://graph.qq.com/oauth2.0/me', access_token=access_token) r = requests.get(graph_url) if r.status_code != 200: raise ThirdPartyFailure("Status %s: %s" % (r.status_code, r.content)) data = loads(r.content[10:-3]) openid = data.get('openid', '') user_info_url = flat_url('https://graph.qq.com/user/get_user_info', access_token=access_token, oauth_consumer_key=self.consumer_key, openid=openid) r = requests.get(user_info_url) if r.status_code != 200: raise ThirdPartyFailure("Status %s: %s" % (r.status_code, r.content)) data = loads(r.content) profile = { 'accounts': [{ 'domain': 'qq.com', 'userid': openid }], 'displayName': data['nickname'], 'preferredUsername': data['nickname'], } cred = {'oauthAccessToken': access_token} return QQAuthenticationComplete(profile=profile, credentials=cred, provider_name=self.name, provider_type=self.type)
def callback(self, request): """Process the VK redirect""" sess_state = request.session.get('state') req_state = request.GET.get('state') if not sess_state or sess_state != req_state: raise CSRFError( 'CSRF Validation check failed. Request state {req_state} is not ' 'the same as session state {sess_state}'.format( req_state=req_state, sess_state=sess_state)) code = request.GET.get('code') if not code: reason = request.GET.get('error_description', 'No reason provided.') return AuthenticationDenied(reason=reason, provider_name=self.name, provider_type=self.type) # Now retrieve the access token with the code access_url = flat_url(PROVIDER_ACCESS_TOKEN_URL, client_id=self.consumer_key, client_secret=self.consumer_secret, redirect_uri=request.route_url( self.callback_route), code=code) r = requests.get(access_url) if r.status_code != 200: raise ThirdPartyFailure('Status {status}: {content}'.format( status=r.status_code, content=r.content)) data = json.loads(r.content) access_token = data['access_token'] # Retrieve profile data graph_url = flat_url( PROVIDER_USER_PROFILE_URL, access_token=access_token, uids=data['user_id'], fields= ('first_name,last_name,nickname,domain,sex,bdate,city,country,timezone,' 'photo,photo_medium,photo_big,photo_rec,has_mobile,mobile_phone,home_phone,' 'rate,contacts,education')) r = requests.get(graph_url) if r.status_code != 200: raise ThirdPartyFailure('Status {status}: {content}'.format( status=r.status_code, content=r.content)) vk_profile = json.loads(r.content)['response'][0] vk_profile['uid'] = data['user_id'] profile = extract_normalize_vk_data(vk_profile) cred = {'oauthAccessToken': access_token} return VKAuthenticationComplete(profile=profile, credentials=cred, provider_name=self.name, provider_type=self.type)
def callback(self, request): """Process the bitbucket redirect""" if 'denied' in request.GET: return AuthenticationDenied("User denied authentication", provider_name=self.name, provider_type=self.type) request_token = oauth.Token.from_string(request.session['token']) verifier = request.GET.get('oauth_verifier') if not verifier: raise ThirdPartyFailure("No oauth_verifier returned") request_token.set_verifier(verifier) # Create the consumer and client, make the request consumer = oauth.Consumer(self.consumer_key, self.consumer_secret) client = oauth.Client(consumer, request_token) resp, content = client.request(ACCESS_URL, "POST") if resp['status'] != '200': raise ThirdPartyFailure("Status %s: %s" % (resp['status'], content)) access_token = dict(parse_qs(content)) cred = {'oauthAccessToken': access_token['oauth_token'][0], 'oauthAccessTokenSecret': access_token['oauth_token_secret'][0]} # Make a request with the data for more user info token = oauth.Token(key=cred['oauthAccessToken'], secret=cred['oauthAccessTokenSecret']) client = oauth.Client(consumer, token) resp, content = client.request(USER_URL) user_data = json.loads(content) data = user_data['user'] # Setup the normalized contact info profile = {} profile['accounts'] = [{ 'domain':'bitbucket.com', 'username':data['username'] }] profile['preferredUsername'] = data['username'] profile['name'] = { 'formatted': '%s %s' % (data['first_name'], data['last_name']), 'givenName': data['first_name'], 'familyName': data['last_name'], } profile['displayName'] = profile['name']['formatted'] return BitbucketAuthenticationComplete(profile=profile, credentials=cred, provider_name=self.name, provider_type=self.type)
def process(self, request): """Handle incoming redirect from OpenID Provider""" log_debug = self.log_debug if log_debug: log.debug('Handling processing of response from server') openid_session = request.session.get('openid_session', None) del request.session['openid_session'] if not openid_session: raise ThirdPartyFailure("No OpenID Session has begun.") # Setup the consumer and parse the information coming back oidconsumer = consumer.Consumer(openid_session, self.openid_store) return_to = request.route_url(self.process_url) info = oidconsumer.complete(request.params, return_to) if info.status in [consumer.FAILURE, consumer.CANCEL]: raise AuthenticationDenied("OpenID failure") elif info.status == consumer.SUCCESS: openid_identity = info.identity_url if info.endpoint.canonicalID: # If it's an i-name, use the canonicalID as its secure even if # the old one is compromised openid_identity = info.endpoint.canonicalID user_data = extract_openid_data( identifier=openid_identity, sreg_resp=sreg.SRegResponse.fromSuccessResponse(info), ax_resp=ax.FetchResponse.fromSuccessResponse(info), ) user_data['end_point'] = get_came_from(request) # Did we get any OAuth info? oauth = info.extensionResponse( 'http://specs.openid.net/extensions/oauth/1.0', False) cred = {} if oauth and 'request_token' in oauth: access_token = self._get_access_token(oauth['request_token']) if access_token: cred.update(access_token) # See if we need to update our profile data with an OAuth call self._update_profile_data(request, user_data, cred) # Delete the temporary token data used for the OpenID auth return self.AuthenticationComplete(profile=user_data, credentials=cred) else: raise ThirdPartyFailure("OpenID failed.")
def weibo_process(request): """Process the weibo redirect""" if request.GET.get('state') != request.session.get('state'): raise CSRFError( "CSRF Validation check failed. Request state %s is " "not the same as session state %s" % (request.GET.get('state'), request.session.get('state'))) config = request.registry.settings code = request.GET.get('code') if not code: reason = request.GET.get('error_reason', 'No reason provided.') return AuthenticationDenied(reason) # Now retrieve the access token with the code r = requests.post( 'https://api.weibo.com/oauth2/access_token', dict(client_id=config['velruse.weibo.app_id'], client_secret=config['velruse.weibo.app_secret'], redirect_uri=request.route_url('weibo_process'), grant_type='authorization_code', code=code)) if r.status_code != 200: raise ThirdPartyFailure("Status %s: %s" % (r.status_code, r.content)) data = loads(r.content) access_token = data['access_token'] uid = data['uid'] # Retrieve profile data graph_url = flat_url('https://api.weibo.com/2/users/show.json', access_token=access_token, uid=uid) r = requests.get(graph_url) if r.status_code != 200: raise ThirdPartyFailure("Status %s: %s" % (r.status_code, r.content)) data = loads(r.content) profile = { 'accounts': [{ 'domain': 'weibo.com', 'userid': data['id'] }], 'gender': data.get('gender'), 'displayName': data['screen_name'], 'preferredUsername': data['name'], } cred = {'oauthAccessToken': access_token} return WeiboAuthenticationComplete(profile=profile, credentials=cred)
def login(self, request): """Initiate a Twitter login""" # Create the consumer and client, make the request consumer = oauth.Consumer(self.consumer_key, self.consumer_secret) sigmethod = oauth.SignatureMethod_HMAC_SHA1() params = {'oauth_callback': request.route_url(self.callback_route)} # We go through some shennanigans here to specify a callback url oauth_request = oauth.Request.from_consumer_and_token( consumer, http_url=REQUEST_URL, parameters=params) oauth_request.sign_request(sigmethod, consumer, None) r = requests.get(REQUEST_URL, headers=oauth_request.to_header()) if r.status_code != 200: raise ThirdPartyFailure("Status %s: %s" % (r.status_code, r.content)) request_token = oauth.Token.from_string(r.content) request.session['token'] = r.content # Send the user to twitter now for authorization req_url = 'https://api.twitter.com/oauth/authenticate' oauth_request = oauth.Request.from_token_and_callback( token=request_token, http_url=req_url) return HTTPFound(location=oauth_request.to_url())
def linkedin_login(request): """Initiate a LinkedIn login""" config = request.registry.settings # Create the consumer and client, make the request consumer = oauth.Consumer(config['velruse.linkedin.consumer_key'], config['velruse.linkedin.consumer_secret']) sigmethod = oauth.SignatureMethod_HMAC_SHA1() params = {'oauth_callback': request.route_url('linkedin_process')} # We go through some shennanigans here to specify a callback url oauth_request = oauth.Request.from_consumer_and_token(consumer, http_url=REQUEST_URL, parameters=params) oauth_request.sign_request(sigmethod, consumer, None) r = requests.get(REQUEST_URL, headers=oauth_request.to_header()) if r.status_code != 200: raise ThirdPartyFailure("Status %s: %s" % (r.status_code, r.content)) request_token = oauth.Token.from_string(r.content) request.session['token'] = r.content # Send the user to linkedin now for authorization if asbool(config.get('velruse.linkedin.authorize')): req_url = 'https://api.linkedin.com/uas/oauth/authorize' else: req_url = 'https://api.linkedin.com/uas/oauth/authenticate' oauth_request = oauth.Request.from_token_and_callback( token=request_token, http_url=req_url) return HTTPFound(location=oauth_request.to_url())
def callback(self, request): """Process the google redirect""" sess_state = request.session.get('state') req_state = request.GET.get('state') if not sess_state or sess_state != req_state: raise CSRFError( 'CSRF Validation check failed. Request state {req_state} is not ' 'the same as session state {sess_state}'.format( req_state=req_state, sess_state=sess_state ) ) code = request.GET.get('code') if not code: reason = request.GET.get('error', 'No reason provided.') return AuthenticationDenied(reason=reason, provider_name=self.name, provider_type=self.type) # Now retrieve the access token with the code r = requests.post('%s://%s/o/oauth2/token' % (self.protocol, self.domain), data={ 'client_id': self.consumer_key, 'client_secret': self.consumer_secret, 'redirect_uri': request.route_url(self.callback_route), 'code': code, 'grant_type': 'authorization_code' }) if r.status_code != 200: raise ThirdPartyFailure("Status %s: %s" % ( r.status_code, r.content)) token_data = loads(r.content) access_token = token_data['access_token'] refresh_token = token_data.get('refresh_token') # Retrieve profile data if scopes allow profile = {} user_url = flat_url( '%s://www.googleapis.com/oauth2/v1/userinfo' % self.protocol, access_token=access_token) r = requests.get(user_url) if r.status_code == 200: data = loads(r.content) profile['accounts'] = [{ 'domain': self.domain, 'username': data['email'], 'userid': data['id'] }] profile['displayName'] = data['name'] profile['preferredUsername'] = data['email'] profile['verifiedEmail'] = data['email'] profile['emails'] = [{'value': data['email']}] cred = {'oauthAccessToken': access_token, 'oauthRefreshToken': refresh_token} return Google2AuthenticationComplete(profile=profile, credentials=cred, provider_name=self.name, provider_type=self.type)
def renren_process(request): """Process the renren redirect""" config = request.registry.settings code = request.GET.get('code') if not code: reason = request.GET.get('error', 'No reason provided.') return AuthenticationDenied(reason) access_url = flat_url('https://graph.renren.com/oauth/token', client_id=config['velruse.renren.app_id'], client_secret=config['velruse.renren.app_secret'], grant_type='authorization_code', redirect_uri=request.route_url('renren_process'), code=code) r = requests.get(access_url) if r.status_code != 200: raise ThirdPartyFailure("Status %s: %s" % (r.status_code, r.content)) data = loads(r.content) access_token = data['access_token'] profile = { 'accounts': [{ 'domain': 'renren.com', 'userid': data['user']['id'] }], 'displayName': data['user']['name'], 'preferredUsername': data['user']['name'], } cred = {'oauthAccessToken': access_token} return RenrenAuthenticationComplete(profile=profile, credentials=cred)
def bitbucket_login(request): """Initiate a bitbucket login""" config = request.registry.settings # Create the consumer and client, make the request consumer = oauth.Consumer(config['velruse.bitbucket.consumer_key'], config['velruse.bitbucket.consumer_secret']) params = {'oauth_callback': request.route_url('bitbucket_process')} # We go through some shennanigans here to specify a callback url oauth_request = oauth.Request.from_consumer_and_token(consumer, http_url=REQUEST_URL, parameters=params) oauth_request.sign_request(SIGMETHOD, consumer, None) r = requests.get(REQUEST_URL, headers=oauth_request.to_header()) if r.status_code != 200: raise ThirdPartyFailure("Status %s: %s" % (r.status_code, r.content)) request_token = oauth.Token.from_string(r.content) request.session['token'] = r.content # Send the user to bitbucket now for authorization # there doesnt seem to be separate url for this on BB if asbool(config.get('velruse.bitbucket.authorize')): req_url = 'https://bitbucket.org/api/1.0/oauth/authenticate/' else: req_url = 'https://bitbucket.org/api/1.0/oauth/authenticate/' oauth_request = oauth.Request.from_token_and_callback(token=request_token, http_url=req_url) return HTTPFound(location=oauth_request.to_url())
def callback(self, request): """Process the github redirect""" code = request.GET.get('code') if not code: reason = request.GET.get('error', 'No reason provided.') return AuthenticationDenied(reason) # Now retrieve the access token with the code access_url = flat_url( 'https://github.com/login/oauth/access_token', client_id=self.consumer_key, client_secret=self.consumer_secret, redirect_uri=request.route_url(self.callback_route), code=code) r = requests.get(access_url) if r.status_code != 200: raise ThirdPartyFailure("Status %s: %s" % ( r.status_code, r.content)) access_token = parse_qs(r.content)['access_token'][0] # Retrieve profile data graph_url = flat_url('https://github.com/api/v2/json/user/show', access_token=access_token) r = requests.get(graph_url) if r.status_code != 200: raise ThirdPartyFailure("Status %s: %s" % ( r.status_code, r.content)) data = loads(r.content)['user'] profile = {} profile['accounts'] = [{ 'domain':'github.com', 'username':data['login'], 'userid':data['id'] }] profile['displayName'] = data['name'] profile['preferredUsername'] = data['login'] # We don't add this to verifiedEmail because ppl can change email # addresses without verifying them if 'email' in data: profile['emails'] = [{'value':data['email']}] cred = {'oauthAccessToken': access_token} return GithubAuthenticationComplete(profile=profile, credentials=cred)
def login(self, request): log_debug = self.log_debug if log_debug: log.debug('Handling OpenID login') # Load default parameters that all Auth Responders take openid_url = request.params.get('openid_identifier') # Let inherited consumers alter the openid identifier if desired openid_url = self._lookup_identifier(request, openid_url) if not openid_url: log.error('Velruse: no openid_url') raise MissingParameter('No openid_identifier was found') openid_session = {} oidconsumer = consumer.Consumer(openid_session, self.openid_store) try: if log_debug: log.debug('About to try OpenID begin') authrequest = oidconsumer.begin(openid_url) except consumer.DiscoveryFailure: if log_debug: log.debug('OpenID begin DiscoveryFailure') raise if authrequest is None: if log_debug: log.debug('OpenID begin returned empty') raise ThirdPartyFailure("OpenID begin returned nothing") if log_debug: log.debug('Updating authrequest') # Update the authrequest self._update_authrequest(request, authrequest) return_to = request.route_url(self.process_url) # OpenID 2.0 lets Providers request POST instead of redirect, this # checks for such a request. if authrequest.shouldSendRedirect(): if log_debug: log.debug('About to initiate OpenID redirect') redirect_url = authrequest.redirectURL(realm=self.realm, return_to=return_to, immediate=False) request.session['openid_session'] = openid_session return HTTPFound(location=redirect_url) else: if log_debug: log.debug('About to initiate OpenID POST') html = authrequest.htmlMarkup( realm=self.realm, return_to=return_to, immediate=False) request.session['openid_session'] = openid_session return Response(body=html)
def callback(self, request): """Process the Yandex redirect""" sess_state = request.session.get('state') req_state = request.GET.get('state') if not sess_state or sess_state != req_state: raise CSRFError( 'CSRF Validation check failed. Request state {req_state} is not ' 'the same as session state {sess_state}'.format( req_state=req_state, sess_state=sess_state)) code = request.GET.get('code') if not code: reason = request.GET.get('error', 'No reason provided.') return AuthenticationDenied(reason=reason, provider_name=self.name, provider_type=self.type) # Now retrieve the access token with the code token_params = { 'grant_type': 'authorization_code', 'code': code, 'client_id': self.consumer_key, 'client_secret': self.consumer_secret, } r = requests.post(PROVIDER_ACCESS_TOKEN_URL, token_params) if r.status_code != 200: raise ThirdPartyFailure('Status {status}: {content}'.format( status=r.status_code, content=r.content)) data = json.loads(r.content) access_token = data['access_token'] # Retrieve profile data profile_url = flat_url(PROVIDER_USER_PROFILE_URL, format='json', oauth_token=access_token) r = requests.get(profile_url) if r.status_code != 200: raise ThirdPartyFailure('Status {status}: {content}'.format( status=r.status_code, content=r.content)) profile = json.loads(r.content) profile = extract_normalize_yandex_data(profile) cred = {'oauthAccessToken': access_token} return YandexAuthenticationComplete(profile=profile, credentials=cred, provider_name=self.name, provider_type=self.type)
def callback(self, request): """Process the facebook redirect""" sess_state = request.session.get('state') req_state = request.GET.get('state') if not sess_state or sess_state != req_state: raise CSRFError( 'CSRF Validation check failed. Request state {req_state} is not ' 'the same as session state {sess_state}'.format( req_state=req_state, sess_state=sess_state)) code = request.GET.get('code') if not code: reason = request.GET.get('error_reason', 'No reason provided.') return AuthenticationDenied(reason=reason, provider_name=self.name, provider_type=self.type) # Now retrieve the access token with the code access_url = flat_url('https://graph.facebook.com/oauth/access_token', client_id=self.consumer_key, client_secret=self.consumer_secret, redirect_uri=request.route_url( self.callback_route), code=code) r = requests.get(access_url) if r.status_code != 200: raise ThirdPartyFailure("Status %s: %s" % (r.status_code, r.content)) access_token = parse_qs(r.content)['access_token'][0] # Retrieve profile data graph_url = flat_url('https://graph.facebook.com/me', access_token=access_token) r = requests.get(graph_url) if r.status_code != 200: raise ThirdPartyFailure("Status %s: %s" % (r.status_code, r.content)) fb_profile = loads(r.content) profile = extract_fb_data(fb_profile) cred = {'oauthAccessToken': access_token} return FacebookAuthenticationComplete(profile=profile, credentials=cred, provider_name=self.name, provider_type=self.type)
def callback(self, request): """Process the Live redirect""" if 'error' in request.GET: raise ThirdPartyFailure( request.GET.get('error_description', 'No reason provided.')) code = request.GET.get('code') if not code: reason = request.GET.get('error_reason', 'No reason provided.') return AuthenticationDenied(reason, provider_name=self.name, provider_type=self.type) # Now retrieve the access token with the code access_url = flat_url('https://oauth.live.com/token', client_id=self.consumer_key, client_secret=self.consumer_secret, redirect_uri=request.route_url( self.callback_route), grant_type="authorization_code", code=code) r = requests.get(access_url) if r.status_code != 200: raise ThirdPartyFailure("Status %s: %s" % (r.status_code, r.content)) data = loads(r.content) access_token = data['access_token'] # Retrieve profile data graph_url = flat_url('https://apis.live.net/v5.0/me', access_token=access_token) r = requests.get(graph_url) if r.status_code != 200: raise ThirdPartyFailure("Status %s: %s" % (r.status_code, r.content)) live_profile = loads(r.content) profile = extract_live_data(live_profile) cred = {'oauthAccessToken': access_token} if 'refresh_token' in data: cred['oauthRefreshToken'] = data['refresh_token'] return LiveAuthenticationComplete(profile=profile, credentials=cred, provider_name=self.name, provider_type=self.type)
def callback(self, request): """Process the douban redirect""" if 'denied' in request.GET: return AuthenticationDenied("User denied authentication", provider_name=self.name, provider_type=self.type) request_token = oauth.Token.from_string(request.session['token']) # Create the consumer and client, make the request consumer = oauth.Consumer(self.consumer_key, self.consumer_secret) client = oauth.Client(consumer, request_token) resp, content = client.request(ACCESS_URL) if resp['status'] != '200': raise ThirdPartyFailure("Status %s: %s" % (resp['status'], content)) access_token = dict(parse_qs(content)) cred = { 'oauthAccessToken': access_token['oauth_token'][0], 'oauthAccessTokenSecret': access_token['oauth_token_secret'][0] } douban_user_id = access_token['douban_user_id'][0] token = oauth.Token(key=cred['oauthAccessToken'], secret=cred['oauthAccessTokenSecret']) client = oauth.Client(consumer, token) resp, content = client.request(USER_URL) user_data = json.loads(content) # Setup the normalized contact info profile = { 'accounts': [{ 'domain': 'douban.com', 'userid': douban_user_id }], 'displayName': user_data['title']['$t'], 'preferredUsername': user_data['title']['$t'], } return DoubanAuthenticationComplete(profile=profile, credentials=cred, provider_name=self.name, provider_type=self.type)
def callback(self, request): """Process the alfresco redirect""" sess_state = request.session.get('state') req_state = request.GET.get('state') if not sess_state or sess_state != req_state: raise CSRFError( 'CSRF Validation check failed. Request state {req_state} is not ' 'the same as session state {sess_state}'.format( req_state=req_state, sess_state=sess_state)) code = request.GET.get('code') if not code: reason = request.GET.get('error', 'No reason provided.') return AuthenticationDenied(reason=reason, provider_name=self.name, provider_type=self.type) # Now retrieve the access token with the code access_url = flat_url('%s://%s/auth/oauth/versions/2/token' % (self.protocol, self.domain)) payload = {} payload['client_id'] = self.consumer_key, payload['client_secret'] = self.consumer_secret, payload['redirect_uri'] = request.route_url(self.callback_route), payload['code'] = code payload['grant_type'] = 'authorization_code' r = requests.post(access_url, data=payload) if r.status_code != 200: raise ThirdPartyFailure("Status %s: %s" % (r.status_code, r.content)) profile = {} profile['accounts'] = [{ 'domain': self.domain, }] cred = { 'access_token': r.json()['access_token'], 'refresh_token': r.json()['refresh_token'] } return AlfrescoAuthenticationComplete(profile=profile, credentials=cred, provider_name=self.name, provider_type=self.type)
def callback(self, request): """Process the renren redirect""" code = request.GET.get('code') if not code: reason = request.GET.get('error', 'No reason provided.') return AuthenticationDenied(reason, provider_name=self.name, provider_type=self.type) access_url = flat_url('https://graph.renren.com/oauth/token', client_id=self.consumer_key, client_secret=self.consumer_secret, grant_type='authorization_code', redirect_uri=request.route_url( self.callback_route), code=code) r = requests.get(access_url) if r.status_code != 200: raise ThirdPartyFailure("Status %s: %s" % (r.status_code, r.content)) data = loads(r.content) access_token = data['access_token'] profile = { 'accounts': [ { 'domain': 'renren.com', 'userid': data['user']['id'] }, ], 'displayName': data['user']['name'], 'preferredUsername': data['user']['name'], } cred = {'oauthAccessToken': access_token} return RenrenAuthenticationComplete(profile=profile, credentials=cred, provider_name=self.name, provider_type=self.type)
def twitter_login(request): """Initiate a Twitter login""" settings = request.registry.settings # Create the consumer and client, make the request consumer = oauth.Consumer(settings['velruse.twitter.consumer_key'], settings['velruse.twitter.consumer_secret']) came_from = get_came_from(request) redirect_uri = request.route_url('twitter_process') if came_from: qs = urlencode({'end_point': came_from}) if not '?' in redirect_uri: redirect_uri += '?' redirect_uri += qs sigmethod = oauth.SignatureMethod_HMAC_SHA1() params = {'oauth_callback': redirect_uri} # We go through some shennanigans here to specify a callback url oauth_request = oauth.Request.from_consumer_and_token(consumer, http_url=REQUEST_URL, parameters=params) oauth_request.sign_request(sigmethod, consumer, None) r = requests.get(REQUEST_URL, headers=oauth_request.to_header()) if r.status_code != 200: raise ThirdPartyFailure("Status %s: %s" % (r.status_code, r.content)) request_token = oauth.Token.from_string(r.content) request.session['token'] = r.content # Send the user to twitter now for authorization if asbool(settings.get('velruse.twitter.authorize')): req_url = 'https://api.twitter.com/oauth/authorize' else: req_url = 'https://api.twitter.com/oauth/authenticate' oauth_request = oauth.Request.from_token_and_callback(token=request_token, http_url=req_url) return HTTPFound(location=oauth_request.to_url())
def login(self, request): """Initiate a douban login""" consumer = oauth.Consumer(self.consumer_key, self.consumer_secret) oauth_request = oauth.Request.from_consumer_and_token( consumer, http_url=REQUEST_URL) oauth_request.sign_request(SIGMETHOD, consumer, None) r = requests.get(REQUEST_URL, headers=oauth_request.to_header()) if r.status_code != 200: raise ThirdPartyFailure("Status %s: %s" % (r.status_code, r.content)) request_token = oauth.Token.from_string(r.content) request.session['token'] = r.content # Send the user to douban now for authorization req_url = 'http://www.douban.com/service/auth/authorize' oauth_request = oauth.Request.from_token_and_callback( token=request_token, callback=request.route_url(self.callback_route), http_url=req_url) return HTTPFound(location=oauth_request.to_url())
def login(self, request): """Initiate a bitbucket login""" # Create the consumer and client, make the request consumer = oauth.Consumer(self.consumer_key, self.consumer_secret) params = {'oauth_callback': request.route_url(self.callback_route)} # We go through some shennanigans here to specify a callback url oauth_request = oauth.Request.from_consumer_and_token(consumer, http_url=REQUEST_URL, parameters=params) oauth_request.sign_request(SIGMETHOD, consumer, None) r = requests.get(REQUEST_URL, headers=oauth_request.to_header()) if r.status_code != 200: raise ThirdPartyFailure("Status %s: %s" % ( r.status_code, r.content)) request_token = oauth.Token.from_string(r.content) request.session['token'] = r.content req_url = 'https://bitbucket.org/api/1.0/oauth/authenticate/' oauth_request = oauth.Request.from_token_and_callback( token=request_token, http_url=req_url) return HTTPFound(location=oauth_request.to_url())
def callback(self, request): session_state = request.session.pop('velruse.state', None) request_state = request.GET.get('state') if not session_state or session_state != request_state: raise CSRFError() code = request.GET.get('code') if not code: return AuthenticationDenied( reason='unknown', # TODO provider_name=self.name, provider_type=self.type) token_url = flat_url( 'https://nid.naver.com/oauth2.0/token', **{ 'grant_type': 'authorization_code', 'client_id': self.consumer_key, 'client_secret': self.consumer_secret, 'redirect_uri': request.route_url(self.callback_route), 'code': code, 'state': request_state, }) r = requests.get( token_url, headers={ 'x-naver-client-id': self.consumer_key, 'x-naver-client-secret': self.consumer_secret, }, ) if r.status_code != 200: raise ThirdPartyFailure('Status {}: {}'.format( r.status_code, r.content)) token_data = r.json() if 'access_token' not in token_data: error = token_data['error'] error_description = token_data['error_description'] raise ThirdPartyFailure('{}: {}'.format(error, error_description)) access_token = token_data['access_token'] r = requests.get('https://openapi.naver.com/v1/nid/me', headers={ 'Authorization': 'Bearer {}'.format(access_token), }) if r.status_code != 200: raise ThirdPartyFailure('Status {}: {}'.format( r.status_code, r.content)) result = r.json() logger.debug('result: %r', result) code = result['resultcode'] message = result['message'] if code != '00': raise ThirdPartyFailure('Fetching profile failed: {} {}'.format( code, message)) profile = result['response'] return NaverAuthenticationComplete(profile=profile, credentials=token_data, provider_name=self.name, provider_type=self.type)
def lastfm_process(request): """Process the LastFM redirect""" if 'error' in request.GET: raise ThirdPartyFailure( request.GET.get('error_description', 'No reason provided.')) config = request.registry.settings api_key = config['velruse.lastfm.api_key'] token = request.GET.get('token') if not token: reason = request.GET.get('error_reason', 'No reason provided.') return AuthenticationDenied(reason) # Now establish a session with the token params = {'method': 'auth.getSession', 'api_key': api_key, 'token': token} signed_params = sign_call(params, config['velruse.lastfm.secret']) session_url = flat_url(API_BASE, format='json', **signed_params) r = requests.get(session_url) if r.status_code != 200: raise ThirdPartyFailure("Status %s: %s" % (r.status_code, r.content)) data = loads(r.content) session = data['session'] cred = {'sessionKey': session['key']} # Fetch the user data user_url = flat_url(API_BASE, format='json', method='user.getInfo', user=session['name'], api_key=api_key) r = requests.get(user_url) if r.status_code != 200: raise ThirdPartyFailure("Status %s: %s" % (r.status_code, r.content)) data = loads(r.content)['user'] profile = { 'displayName': data['name'], 'gender': 'male' if data['gender'] == 'm' else 'female', 'name': { 'formatted': data.get('realname'), }, 'urls': { 'type': 'profile', 'value': data.get('url') }, 'photos': [], 'accounts': [{ 'domain': 'last.fm', 'username': session['name'], 'userid': data['id'] }] } images = {} for img in data.get('image', []): images[img['size']] = img['#text'] if 'medium' in images: profile['photos'].append({ 'type': 'thumbnail', 'value': images['medium'] }) larger = images.get('extralarge', images.get('large')) if larger: profile['photos'].append({'type': '', 'value': larger}) return LastFMAuthenticationComplete(profile=profile, credentials=cred)
def callback(self, request): """Process the MailRu redirect""" state = request.session.get('state') if not state or state != request.GET.get('state'): raise CSRFError( 'CSRF Validation check failed. Request state {req_state} is not ' 'the same as session state {sess_state}'.format( req_state=request.GET.get('state'), sess_state=request.session.get('state'))) code = request.GET.get('code') if not code: reason = request.GET.get('error', 'No reason provided.') return AuthenticationDenied(reason=reason, provider_name=self.name, provider_type=self.type) # Now retrieve the access token with the code access_params = dict( grant_type='authorization_code', code=code, client_id=self.consumer_key, client_secret=self.consumer_secret, redirect_uri=request.route_url(self.callback_route), ) r = requests.post(PROVIDER_ACCESS_TOKEN_URL, access_params) if r.status_code != 200: raise ThirdPartyFailure('Status {status}: {content}'.format( status=r.status_code, content=r.content)) data = json.loads(r.content) access_token = data['access_token'] # Retrieve profile data. # Mail.ru API requires a special parameter 'sig' which must be composed # by the following sequence signature = hashlib.md5( 'app_id={client_id}' 'method={method}' 'secure=1' 'session_key={access_token}' '{secret_key}'.format( client_id=self.consumer_key, method=PROVIDER_USER_PROFILE_API_METHOD, access_token=access_token, secret_key=self.consumer_secret)).hexdigest() # Read more about the following params on # http://api.mail.ru/docs/guides/restapi/#params profile_url = flat_url(PROVIDER_USER_PROFILE_URL, method=PROVIDER_USER_PROFILE_API_METHOD, app_id=self.consumer_key, sig=signature, session_key=access_token, secure=1) r = requests.get(profile_url) if r.status_code != 200: raise ThirdPartyFailure('Status {status}: {content}'.format( status=r.status_code, content=r.content)) profile = json.loads(r.content)[0] profile = extract_normalize_mailru_data(profile) cred = {'oauthAccessToken': access_token} return MailRuAuthenticationComplete(profile=profile, credentials=cred, provider_name=self.name, provider_type=self.type)