def openid_server(request): """ This view is the actual OpenID server - running at the URL pointed to by the <link rel="openid.server"> tag. """ server = Server(get_store(request), op_endpoint=request.build_absolute_uri( reverse('openid-provider-root'))) # Cancellation if 'cancel' in request.REQUEST: if 'OPENID_REQUEST' in request.session: return oresponse_to_response(server, request.session['OPENID_REQUEST'].answer(False)) else: return HttpResponseRedirect('/') # Clear AuthorizationInfo session var, if it is set if request.session.get('AuthorizationInfo', None): del request.session['AuthorizationInfo'] querydict = dict(request.REQUEST.items()) try: orequest = server.decodeRequest(querydict) except ProtocolError, why: logger.error('Invalid OpenID message %s' % querydict) return oresponse_to_response(server, why)
def __init__(self, base_url): self.store = MemoryStore() self.identity_url = base_url + 'identity' self.localid_url = base_url + 'localid' self.endpoint_url = base_url + 'endpoint' self.server = Server(self.store, self.endpoint_url) self.last_request = None
def __init__(self, base_url): self.store = MemoryStore() self.identity_url = base_url + 'identity' self.localid_url = base_url + 'localid' self.endpoint_url = base_url + 'endpoint' self.server = Server(self.store, self.endpoint_url) self.last_request = None self.type_uris = ['http://specs.openid.net/auth/2.0/signon']
def openid_decide(request): """ The page that asks the user if they really want to sign in to the site, and lets them add the consumer to their trusted whitelist. # If user is logged in, ask if they want to trust this trust_root # If they are NOT logged in, show the landing page """ custom_log(request, "User entered openid_decide page", level="debug") server = Server(get_store(request), op_endpoint=request.build_absolute_uri(reverse('openid-provider-root'))) orequest = server.decodeRequest(request.session.get('OPENID_REQUEST')) trust_root_valid = request.session.get('OPENID_TRUSTROOT_VALID') if not (request.browser and request.browser.user and request.browser.is_authenticated() and request.user.is_authenticated()): custom_log(request, "User is not authenticated. Redirect to sign-in page", level="debug") return landing_page(request, orequest) if not orequest: custom_log(request, "Entered decide page with no OpenID session in progress", level="warn") return error_page(request, "You don't have OpenID login session in progress.") openid = openid_get_identity(request, orequest.identity) if openid is None: custom_log(request, "No OpenID exists for user %s" % request.browser.user, level="warn") return error_page( request, "You are signed in but you don't have OpenID here!") if request.method == 'POST' and request.POST.get('decide_page', False): if request.POST.get("cancel"): custom_log(request, "User cancelled authentication from the decide page", level="info") for k in ["AuthorizationInfo", "OPENID_TRUSTROOT_VALID", "OPENID_REQUEST", get_trust_session_key(orequest)]: try: del request.session[k] except KeyError: pass custom_log(request, "Cancelled. Redirect to front page", level="debug") return HttpResponseRedirect(reverse("login_frontend.views.indexview")) (obj, created) = TrustedRoot.objects.get_or_create( openid=openid, trust_root=orequest.trust_root) if created: custom_log(request, "Created a new TrustRoot for %s" % orequest.trust_root) else: custom_log(request, "Old TrustRoot for %s exists" % orequest.trust_root) if not conf.FAILED_DISCOVERY_AS_VALID: custom_log(request, "Setting %s=True" % (get_trust_session_key(orequest)), level="debug") request.session[get_trust_session_key(orequest)] = True custom_log(request, "Redirecting to OpenID server root", level="debug") return HttpResponseRedirect(reverse('openid-provider-root')) custom_log(request, "Showing decide page", level="info") return render_to_response('openid_provider/decide.html', { 'title': _('Trust this site?'), 'trust_root': orequest.trust_root, 'trust_root_valid': trust_root_valid, 'return_to': orequest.return_to, 'identity': orequest.identity, 'sreg': get_default_sreg_data(request, orequest), }, context_instance=RequestContext(request))
def openid_server(req): """ This view is the actual OpenID server - running at the URL pointed to by the <link rel="openid.server"> tag. """ host = get_base_uri(req) try: # if we have django_openid_auth in applications directory # then we can use DjangoOpenIDStore from django_openid_auth.store import DjangoOpenIDStore store = DjangoOpenIDStore() except: # otherwise use FileOpenIDStore OPENID_FILESTORE = '/tmp/openid-filestore' from openid.store.filestore import FileOpenIDStore store = FileOpenIDStore(OPENID_FILESTORE) server = Server(store, op_endpoint="%s%s" % (host, reverse('openid-provider-root'))) # Clear AuthorizationInfo session var, if it is set if req.session.get('AuthorizationInfo', None): del req.session['AuthorizationInfo'] querydict = dict(req.REQUEST.items()) orequest = server.decodeRequest(querydict) if not orequest: orequest = req.session.get('OPENID_REQUEST', None) if not orequest: # not request, render info page: return render_to_response('openid_provider/server.html', {'host': host,}, context_instance=RequestContext(req)) else: # remove session stored data: del req.session['OPENID_REQUEST'] if orequest.mode in ("checkid_immediate", "checkid_setup"): if not req.user.is_authenticated(): return landing_page(req, orequest) #openid = openid_is_authorized(req, orequest.identity, orequest.trust_root) #if openid is not None: oresponse = orequest.answer(True, identity="%s%s" % ( host, reverse('openid-provider-identity', args=[req.user.username]))) fullname = "%s %s" % (req.user.first_name, req.user.last_name) if fullname == " ": fullname = req.user.username if fullname.strip().find(" ") == -1: fullname = "%s %s" % (fullname, fullname) sreg_data = { 'fullname': fullname , 'email': req.user.email, 'nickname': req.user.username, } sreg_req = sreg.SRegRequest.fromOpenIDRequest(orequest) sreg_resp = sreg.SRegResponse.extractResponse(sreg_req, sreg_data) oresponse.addExtension(sreg_resp) #elif orequest.immediate: # raise Exception('checkid_immediate mode not supported') #else: # req.session['OPENID_REQUEST'] = orequest # return HttpResponseRedirect(reverse('openid-provider-decide')) else: oresponse = server.handleRequest(orequest) webresponse = server.encodeResponse(oresponse) return django_response(webresponse)
def openid_decide(request): """ The page that asks the user if they really want to sign in to the site, and lets them add the consumer to their trusted whitelist. # If user is logged in, ask if they want to trust this trust_root # If they are NOT logged in, show the landing page """ custom_log(request, "User entered openid_decide page", level="debug") server = Server(get_store(request), op_endpoint=request.build_absolute_uri(reverse('openid-provider-root'))) orequest = server.decodeRequest(request.session.get('OPENID_REQUEST')) trust_root_valid = request.session.get('OPENID_TRUSTROOT_VALID') if not (request.browser and request.browser.user and request.browser.is_authenticated() and request.user.is_authenticated()): custom_log(request, "User is not authenticated. Redirect to sign-in page", level="debug") return landing_page(request, orequest) openid = openid_get_identity(request, orequest.identity) if openid is None: custom_log(request, "No OpenID exists for user %s" % request.browser.user, level="warn") return error_page( request, "You are signed in but you don't have OpenID here!") if request.method == 'POST' and request.POST.get('decide_page', False): if request.POST.get("cancel"): custom_log(request, "User cancelled authentication from the decide page", level="info") for k in ["AuthorizationInfo", "OPENID_TRUSTROOT_VALID", "OPENID_REQUEST", get_trust_session_key(orequest)]: try: del request.session[k] except KeyError: pass custom_log(request, "Cancelled. Redirect to front page", level="debug") return HttpResponseRedirect(reverse("login_frontend.views.indexview")) (obj, created) = TrustedRoot.objects.get_or_create( openid=openid, trust_root=orequest.trust_root) if created: custom_log(request, "Created a new TrustRoot for %s" % orequest.trust_root) else: custom_log(request, "Old TrustRoot for %s exists" % orequest.trust_root) if not conf.FAILED_DISCOVERY_AS_VALID: custom_log(request, "Setting %s=True" % (get_trust_session_key(orequest)), level="debug") request.session[get_trust_session_key(orequest)] = True custom_log(request, "Redirecting to OpenID server root", level="debug") return HttpResponseRedirect(reverse('openid-provider-root')) custom_log(request, "Showing decide page", level="info") return render_to_response('openid_provider/decide.html', { 'title': _('Trust this site?'), 'trust_root': orequest.trust_root, 'trust_root_valid': trust_root_valid, 'return_to': orequest.return_to, 'identity': orequest.identity, 'sreg': get_default_sreg_data(request, orequest), }, context_instance=RequestContext(request))
def __init__(self, request): self.request = request self.openid_server = Server(SFOpenIDStore(self.request.db_session), request.route_url('openid_provider')) userid = authenticated_userid(request) self.auth_userid = userid or request.session.get('auth_userid') if self.auth_userid: query = self.request.db_session.query(UserProfile) self.auth_user = query.get(self.auth_userid) else: self.auth_user = None
def setUp(self): super(TestGetMacaroonNS, self).setUp() params = { 'openid.mode': 'checkid_setup', 'openid.trust_root': 'http://localhost/', 'openid.return_to': 'http://localhost/', 'openid.identity': IDENTIFIER_SELECT, } openid_store = getUtility(IOpenIDConsumerStore) openid_server = Server(openid_store, get_server_url()) self.orequest = openid_server.decodeRequest(params)
def test_fromSuccessResponse_no_signed(self): params = { 'openid.mode': 'checkid_setup', 'openid.trust_root': 'http://localhost/', 'openid.return_to': 'http://localhost/', 'openid.identity': IDENTIFIER_SELECT, } openid_store = getUtility(IOpenIDConsumerStore) openid_server = Server(openid_store, get_server_url()) orequest = openid_server.decodeRequest(params) success_resp = SuccessResponse(orequest, orequest.message) resp = MacaroonResponse.fromSuccessResponse(success_resp) self.assertIsNone(resp.discharge_macaroon_raw)
def test_fromOpenIDRequest(self): params = { 'openid.mode': 'checkid_setup', 'openid.trust_root': 'http://localhost/', 'openid.return_to': 'http://localhost/', 'openid.identity': IDENTIFIER_SELECT, } openid_store = getUtility(IOpenIDConsumerStore) openid_server = Server(openid_store, get_server_url()) orequest = openid_server.decodeRequest(params) req = MacaroonRequest.fromOpenIDRequest(orequest) self.assertIsNone(req.caveat_id) self.assertEqual(MACAROON_NS, req.ns_uri)
def getServer(request): """ Get a Server object to perform OpenID authentication. """ endpoint_url = request.build_absolute_uri(reverse('server:endpoint')) # Method `build_absolute_uri` returns str in both python 2 and 3, convert to text_type in 2.7 if isinstance(endpoint_url, six.binary_type): endpoint_url = endpoint_url.decode('utf-8') return Server(getOpenIDStore(), endpoint_url)
def endpoint(request): """ Respond to low-level OpenID protocol messages. """ s = Server(OpenIDStore(), request.build_absolute_uri(reverse(endpoint))) query = request.GET or request.POST # First, decode the incoming request into something the OpenID # library can use. try: openid_request = s.decodeRequest(query) except ProtocolError, why: # This means the incoming request was invalid. return direct_to_template( request, 'endpoint.html', {'error': str(why)})
def endpoint(): endpoint_url = url_for('.endpoint', _external=True) openid = OpenIDServer(OpenIDStore(), endpoint_url) query = request.args if request.method == 'GET' else request.form try: oid_req = openid.decodeRequest(query) except ProtocolError as e: return openid_exception(e) if not oid_req: return render_template('papersplease/openid/index.html') if oid_req.mode in ('checkid_immediate', 'checkid_setup'): if current_user.is_authenticated(): return openid_response(openid, oid_req.answer(True)) elif oid_req.immediate: return openid_response(openid, oid_req.answer(False)) else: return login_manager.unauthorized() else: return openid_response(openid, openid.handleRequest(oid_req))
def display_response(request, openid_response): """ Display an OpenID response. Errors will be displayed directly to the user; successful responses and other protocol-level messages will be sent using the proper mechanism (i.e., direct response, redirection, etc.). """ s = Server(OpenIDStore(), request.build_absolute_uri(reverse(endpoint))) # Encode the response into something that is renderable. try: webresponse = s.encodeResponse(openid_response) except EncodingError, why: # If it couldn't be encoded, display an error. text = why.response.encodeToKVForm() return direct_to_template( request, 'endpoint.html', {'error': cgi.escape(text)})
def prep_response(request, orequest, oresponse, server=None): # Convert a webresponse from the OpenID library in to a Django HttpResponse if not server: server = Server(get_store(request), op_endpoint=request.build_absolute_uri( reverse('openid-provider-root'))) webresponse = server.encodeResponse(oresponse) if webresponse.code == 200 and orequest.mode in BROWSER_REQUEST_MODES: response = render_to_response('openid_provider/response.html', { 'body': webresponse.body, }, context_instance=RequestContext(request)) logger.debug('rendering browser response') else: response = HttpResponse(webresponse.body) response.status_code = webresponse.code for key, value in webresponse.headers.items(): response[key] = value logger.debug('rendering raw response') return response
def index(): oidstore = Web2pyStore(db) cache.ram('oid_cleanup', lambda: oidstore.cleanup(), time_expire=25200) #call cleanup approx. every 7h oserver = Server(oidstore, OID_SERVER) orequest = oserver.decodeRequest(request.vars) #if another controller asked to cancel this authentication request do so if session.oid_cancel: session.oid_cancel = None return redirect(orequest.getCancelURL()) user_is_logged_in = auth.is_logged_in() user_owns_id = user_is_logged_in and auth.user['nickname'] == orequest.identity.split('/').pop().lower() #lazy eval user_trusts_root = user_is_logged_in and _userTrustsRoot(orequest.trust_root) #lazy eval if orequest.mode in ['checkid_immediate', 'checkid_setup']: if user_is_logged_in and user_owns_id and user_trusts_root: resp = orequest.answer(True) elif orequest.immediate: resp = orequest.answer(False) else: #populate oid session with details as required by other controllers such as the url to #redirect to after logon or after approving data transfer to the relying party. session.oid_url = URL(r=request, args=request.args, vars=request.vars) #redirect user to authenticate herself or to authorise request if user_is_logged_in: session.oid_orequest = orequest session.oid_user_owns_id = user_owns_id return redirect(URL(r=request, c='auth', f='data')) else: return redirect(URL(r=request, c='auth', f='user', args=['login'])) else: #let the library handle it resp = oserver.handleRequest(orequest) oresp = oserver.encodeResponse(resp) if oresp.code==200: return oresp.body else: return redirect(oresp.headers['location'], oresp.code)
def init_idp(self): self.datastore = OpenIDStore(self.get_config_value('database url')) self.server = Server(self.datastore, op_endpoint=self.endpoint_url) # Expose OpenID presence in the root headers = self._root.default_headers headers['X-XRDS-Location'] = self.endpoint_url + 'XRDS' html_heads = self._root.html_heads HEAD_LINK = '<link rel="%s" href="%s">' openid_heads = [ HEAD_LINK % ('openid2.provider', self.endpoint_url), HEAD_LINK % ('openid.server', self.endpoint_url) ] html_heads['openid'] = openid_heads
class OpenIDApp(object): def __init__(self): from openid.server.server import Server from openid.store.memstore import MemoryStore store = MemoryStore() self.server = Server(store, 'http://www.jaraco.com/') def __call__(self, environ, start_response): """ The WSGI App - verifies the identity against the requested identity """ start_response("200 OK", [('Content-Type', 'text/html')]) return ["foo"] query = dict(urlparse.parse_qsl(environ['QUERY_STRING'])) request = self.server.decodeRequest(query) if not request: path_info = environ['PATH_INFO'] if path_info: username = path_info.rsplit('/', 1)[-1] start_response("200 OK", [('Content-Type', 'text/html')]) provider = 'http://drake.jaraco.com/isapi-openid' local_id = '%(provider)s/%(username)s' % vars() return [ """<HTML><HEAD><LINK rel="openid2.provider" href="%(provider)s"><LINK rel="openid2.local_id" href="%(local_id)s"></HEAD><BODY>Id for %(username)s</BODY></HTML>""" % vars() ] else: start_response("401 Unauthorized") return [""] id_requested = request.identity.rsplit('/', 1)[-1] # assume the user has already authenticated using basic auth id_authenticated = environ['REMOTE_USER'].rsplit('\\', 1)[-1] matched = id_requested and id_requested == id_authenticated response = request.answer(matched) start_response("303 found", [('Location', response.encodeToURL())]) return ['']
class OpenIDProvider(object): # OpenID service type URIs, listed in order of preference. The # ordering of this list affects yadis and XRI service discovery. openid_type_uris = [ #discover.OPENID_IDP_2_0_TYPE, discover.OPENID_2_0_TYPE, discover.OPENID_1_1_TYPE, discover.OPENID_1_0_TYPE, sreg.ns_uri, ] def __init__(self, request): self.request = request self.openid_server = Server(SFOpenIDStore(self.request.db_session), request.route_url('openid_provider')) userid = authenticated_userid(request) self.auth_userid = userid or request.session.get('auth_userid') if self.auth_userid: query = self.request.db_session.query(UserProfile) self.auth_user = query.get(self.auth_userid) else: self.auth_user = None def process(self, request_params): logger.debug('Processing openid request: %s', request_params) if request_params.get('openid.identity'): home_url = self.request.route_url('home') if request_params['openid.identity'] == request_params['openid.claimed_id'] and \ request_params['openid.identity'] == home_url: username = self.request.user and self.request.user.username or \ self.auth_userid if username: username = username.lower() user_url = self.request.route_url('user_profile', username=username) request_params['openid.identity'] = user_url request_params['openid.claimed_id'] = user_url try: openid_request = self.openid_server.decodeRequest(request_params) # MalformedReturnURL, UntrustedReturnURL, etc. except ProtocolError as e: logger.info('Unable to decode request: %s %s', e.__class__, e.openid_message) return '' logger.debug('Decoded request: %s', openid_request) if openid_request is None: return '' if openid_request.mode in ["checkid_immediate", "checkid_setup"]: if self.request.user or self.auth_userid: openid_response = self.handleCheckIDRequest(openid_request) else: # If the user has not logged in yet, stash the OpenID # consuming site request (if there isn't one already) and # send them to the login view. The openid_tween will take # care of sending them back to the OpenID consuming site. rp_dict = dict(request_params.items()) self.request.session['openid_request'] = rp_dict self.request.session.save() return HTTPFound(location=self.request.route_url('login')) else: openid_response = self.openid_server.handleRequest(openid_request) logger.debug('Decoded response: %s', openid_response) encoded_response = self.openid_server.encodeResponse(openid_response) if 'location' in encoded_response.headers: response = HTTPFound(location=encoded_response.headers['location']) return response return encoded_response.body def get(self): return self.process(self.request.GET) def post(self): if self.request.method != "POST": return HTTPMethodNotAllowed() return self.process(self.request.POST) def approved(self, request, identifier=None): response = request.answer(True, identity=identifier) self.addSRegResponse(request, response) return response def handleCheckIDRequest(self, request): is_authorized = self.isAuthorized(request.identity, request.trust_root) if is_authorized: return self.approved(request, request.identity) else: return request.answer(False, identity=request.identity) def isAuthorized(self, identity_url, trust_root): if not self.auth_userid: return False self.request.registry.notify( CheckIDAuthorized(self.request, self.auth_user)) # TODO: prompt user for authorization return True def addSRegResponse(self, request, response): sreg_req = sreg.SRegRequest.fromOpenIDRequest(request) sreg_data = dict([(fname, None) for fname in sreg.data_fields]) sreg_data['fullname'] = '%s %s' % (self.auth_user.first_name, self.auth_user.last_name) sreg_data['nickname'] = self.auth_userid sreg_data['email'] = self.auth_user.email sreg_resp = sreg.SRegResponse.extractResponse(sreg_req, sreg_data) response.addExtension(sreg_resp) def identity(self): query = self.request.db_session.query(UserProfile) target_username = self.request.matchdict['username'] target_user = query.get(target_username) if target_user is None: raise HTTPNotFound() return { 'username': target_user.username.lower(), }
class OpenIDMixin: """A mixin with OpenID helper methods.""" openid_request = None def __init__(self, context, request): super(OpenIDMixin, self).__init__(context, request) self.server_url = get_server_url() self.openid_server = Server(openid_store, self.server_url) @property def user_identity_url(self): return ITestOpenIDPersistentIdentity(self.account).openid_identity_url def isIdentityOwner(self): """Return True if the user can authenticate as the given ID.""" assert self.account is not None, "user should be logged in by now." return (self.openid_request.idSelect() or self.openid_request.identity == self.user_identity_url) @cachedproperty def openid_parameters(self): """A dictionary of OpenID query parameters from request.""" query = {} for key, value in self.request.form.items(): if key.startswith('openid.'): # All OpenID query args are supposed to be ASCII. query[key.encode('US-ASCII')] = value.encode('US-ASCII') return query def getSession(self): """Get the session data container that stores the OpenID request.""" if IUnauthenticatedPrincipal.providedBy(self.request.principal): # A dance to assert that we want to break the rules about no # unauthenticated sessions. Only after this next line is it # safe to set session values. allowUnauthenticatedSession(self.request, duration=timedelta(minutes=60)) return ISession(self.request)[SESSION_PKG_KEY] def restoreRequestFromSession(self): """Get the OpenIDRequest from our session.""" session = self.getSession() cache = get_property_cache(self) try: cache.openid_parameters = session[OPENID_REQUEST_SESSION_KEY] except KeyError: raise UnexpectedFormData("No OpenID request in session") # Decode the request parameters and create the request object. self.openid_request = self.openid_server.decodeRequest( self.openid_parameters) assert zisinstance( self.openid_request, CheckIDRequest), ('Invalid OpenIDRequest in session') def saveRequestInSession(self): """Save the OpenIDRequest in our session.""" query = self.openid_parameters assert query.get('openid.mode') == 'checkid_setup', ( 'Can only serialise checkid_setup OpenID requests') session = self.getSession() # If this was meant for use in production we'd have to use a nonce # as the key when storing the openid request in the session, but as # it's meant to run only on development instances we can simplify # things a bit by storing the openid request using a well known key. session[OPENID_REQUEST_SESSION_KEY] = query def renderOpenIDResponse(self, openid_response): """Return a web-suitable response constructed from openid_response.""" webresponse = self.openid_server.encodeResponse(openid_response) response = self.request.response response.setStatus(webresponse.code) # encodeResponse doesn't generate a content-type, help it out if (webresponse.code == 200 and webresponse.body and openid_response.whichEncoding() == ENCODE_HTML_FORM): response.setHeader('content-type', 'text/html') for header, value in webresponse.headers.items(): response.setHeader(header, value) return webresponse.body def createPositiveResponse(self): """Create a positive assertion OpenIDResponse. This method should be called to create the response to successful checkid requests. If the trust root for the request is in openid_sreg_trustroots, then additional user information is included with the response. """ assert self.account is not None, ( 'Must be logged in for positive OpenID response') assert self.openid_request is not None, ( 'No OpenID request to respond to.') if not self.isIdentityOwner(): return self.createFailedResponse() if self.openid_request.idSelect(): response = self.openid_request.answer( True, identity=self.user_identity_url) else: response = self.openid_request.answer(True) person = IPerson(self.account) sreg_fields = dict(nickname=person.name, email=person.preferredemail.email, fullname=self.account.displayname) sreg_request = SRegRequest.fromOpenIDRequest(self.openid_request) sreg_response = SRegResponse.extractResponse(sreg_request, sreg_fields) response.addExtension(sreg_response) return response def createFailedResponse(self): """Create a failed assertion OpenIDResponse. This method should be called to create the response to unsuccessful checkid requests. """ assert self.openid_request is not None, ( 'No OpenID request to respond to.') response = self.openid_request.answer(False, self.server_url) return response
def openid_server(req): """ This view is the actual OpenID server - running at the URL pointed to by the <link rel="openid.server"> tag. """ host = get_base_uri(req) try: # if we have django_openid_auth in applications directory # then we can use DjangoOpenIDStore from django_openid_auth.store import DjangoOpenIDStore store = DjangoOpenIDStore() except: # otherwise use FileOpenIDStore OPENID_FILESTORE = '/tmp/openid-filestore' from openid.store.filestore import FileOpenIDStore store = FileOpenIDStore(OPENID_FILESTORE) server = Server(store, op_endpoint="%s%s" % (host, reverse('openid-provider-root'))) # Clear AuthorizationInfo session var, if it is set if req.session.get('AuthorizationInfo', None): del req.session['AuthorizationInfo'] querydict = dict(req.REQUEST.items()) try: orequest = server.decodeRequest(querydict) except: L.exception("Request decode failed") orequest = None if not orequest: orequest = req.session.get('OPENID_REQUEST', None) if not orequest: # not request, render info page: return render_to_response('openid_provider/server.html', { 'host': host, }, context_instance=RequestContext(req)) else: # remove session stored data: del req.session['OPENID_REQUEST'] if orequest.mode in ("checkid_immediate", "checkid_setup"): if not req.user.is_authenticated(): return landing_page(req, orequest) openid = openid_is_authorized(req, orequest.identity, orequest.trust_root) if openid is not None: oresponse = orequest.answer( True, identity="%s%s" % (host, reverse('openid-provider-identity', args=[openid.openid]))) sreg_data = {'nickname': req.user.username} sreg_req = sreg.SRegRequest.fromOpenIDRequest(orequest) sreg_resp = sreg.SRegResponse.extractResponse(sreg_req, sreg_data) oresponse.addExtension(sreg_resp) elif orequest.immediate: raise Exception('checkid_immediate mode not supported') else: req.session['OPENID_REQUEST'] = orequest return HttpResponseRedirect(reverse('openid-provider-decide')) else: oresponse = server.handleRequest(orequest) webresponse = server.encodeResponse(oresponse) return django_response(webresponse)
def getServer(request): """ Get a Server object to perform OpenID authentication. """ return Server(getOpenIDStore(), getViewURL(request, endpoint))
def get_openid_server(request): store = DjangoDBOpenIDStore() return Server(store, endpoint_url(request))
def openid_get_server(request): return Server(get_store(request), op_endpoint=request.build_absolute_uri( reverse('openid-provider-root')))
def getServer(request): """ Get a Server object to perform OpenID authentication. """ endpoint_url = request.build_absolute_uri(reverse('server:endpoint')) return Server(getOpenIDStore(), endpoint_url)
def get_server(request): """ Get a Server object to perform OpenID authentication. """ return Server(get_openid_store(), get_view_url(request, endpoint))
def __init__(self, context, request): super(OpenIDMixin, self).__init__(context, request) self.server_url = get_server_url() self.openid_server = Server(openid_store, self.server_url)
def cgi_main(): logger.html_mode() global config cgi_request = CGIParser() response = CGIResponse() # Load configuration config_file = ConfigManager.find_config_file() if not config_file: logger.error("No configuration file found") response.type = "no_config" response.output(None) return else: try: config = ConfigManager(config_file) except configparser.ParsingError as e: logger.error("Unable to parse config file: {0}".format(err)) response.error = "Error parsing poit configuration file" if config: # Make sure an endpoint is set endpoint = config.get_option("server", "endpoint") if not endpoint: endpoint = cgi_request.self_uri(https=config.force_https()) config.set_option("server", "endpoint", endpoint, save=False) logger.debug("Endpoint: " + endpoint) ostore = FileOpenIDStore(os.path.expanduser(config.get_option("server", "session_dir"))) oserver = OpenIDServer(ostore, endpoint) logger.debug("Initialized server") else: # Stilll need to create a OpenIDServer to parse the request ostore = MemoryStore() oserver = OpenIDServer(ostore, "") logger.debug("Initialized dummy server") # Decode request try: request = oserver.decodeRequest(cgi_request.openid) except server.ProtocolError as err: logger.warn("Not an OpenID request: " + str(err)) request = None session = Session(cgi_request) # Redirect to HTTPS if required if (not session.is_secure()) and config.force_https() and ((not request) or type(request) == CheckIDRequest): response.redirect_url = "{endpoint}?{fields}".format( endpoint=re.sub("^http:", "https:", endpoint), fields=urllib.urlencode(cgi_request.openid) ) response.output(session) return action = PoitAction.from_request(cgi_request.post) logger.debug("Action: " + str(action)) if action and action.type == "authenticate" and not session.authenticated: session.authenticated = True if request: handle_openid(session, oserver, request, response, action) else: handle_normal(session, response, action) config.save() ostore.cleanup() response.output(session)
def get_server(self, request): return Server(DjangoOpenIDStore())
def provider_login(request): """ OpenID login endpoint """ # make and validate endpoint endpoint = get_xrds_url('login', request) if not endpoint: return default_render_failure(request, "Invalid OpenID request") # initialize store and server store = DjangoOpenIDStore() server = Server(store, endpoint) # first check to see if the request is an OpenID request. # If so, the client will have specified an 'openid.mode' as part # of the request. querydict = dict(request.REQUEST.items()) error = False if 'openid.mode' in request.GET or 'openid.mode' in request.POST: # decode request try: openid_request = server.decodeRequest(querydict) except (UntrustedReturnURL, ProtocolError): openid_request = None if not openid_request: return default_render_failure(request, "Invalid OpenID request") # don't allow invalid and non-trusted trust roots if not validate_trust_root(openid_request): return default_render_failure(request, "Invalid OpenID trust root") # checkid_immediate not supported, require user interaction if openid_request.mode == 'checkid_immediate': return provider_respond(server, openid_request, openid_request.answer(False), {}) # checkid_setup, so display login page # (by falling through to the provider_login at the # bottom of this method). elif openid_request.mode == 'checkid_setup': if openid_request.idSelect(): # remember request and original path request.session['openid_setup'] = { 'request': openid_request, 'url': request.get_full_path() } # user failed login on previous attempt if 'openid_error' in request.session: error = True del request.session['openid_error'] # OpenID response else: return provider_respond(server, openid_request, server.handleRequest(openid_request), {}) # handle login redirection: these are also sent to this view function, # but are distinguished by lacking the openid mode. We also know that # they are posts, because they come from the popup elif request.method == 'POST' and 'openid_setup' in request.session: # get OpenID request from session openid_setup = request.session['openid_setup'] openid_request = openid_setup['request'] openid_request_url = openid_setup['url'] del request.session['openid_setup'] # don't allow invalid trust roots if not validate_trust_root(openid_request): return default_render_failure(request, "Invalid OpenID trust root") # check if user with given email exists # Failure is redirected to this method (by using the original URL), # which will bring up the login dialog. email = request.POST.get('email', None) try: user = User.objects.get(email=email) except User.DoesNotExist: request.session['openid_error'] = True msg = "OpenID login failed - Unknown user email: %s" AUDIT_LOG.warning(msg, email) return HttpResponseRedirect(openid_request_url) # attempt to authenticate user (but not actually log them in...) # Failure is again redirected to the login dialog. username = user.username password = request.POST.get('password', None) try: user = authenticate(username=username, password=password, request=request) except RateLimitException: AUDIT_LOG.warning('OpenID - Too many failed login attempts.') return HttpResponseRedirect(openid_request_url) if user is None: request.session['openid_error'] = True msg = "OpenID login failed - password for %s is invalid" AUDIT_LOG.warning(msg, email) return HttpResponseRedirect(openid_request_url) # authentication succeeded, so fetch user information # that was requested if user is not None and user.is_active: # remove error from session since login succeeded if 'openid_error' in request.session: del request.session['openid_error'] AUDIT_LOG.info("OpenID login success - %s (%s)", user.username, user.email) # redirect user to return_to location url = endpoint + urlquote(user.username) response = openid_request.answer(True, None, url) # TODO: for CS50 we are forcibly returning the username # instead of fullname. In the OpenID simple registration # extension, we don't have to return any fields we don't # want to, even if they were marked as required by the # Consumer. The behavior of what to do when there are # missing fields is up to the Consumer. The proper change # should only return the username, however this will likely # break the CS50 client. Temporarily we will be returning # username filling in for fullname in addition to username # as sreg nickname. # Note too that this is hardcoded, and not really responding to # the extensions that were registered in the first place. results = { 'nickname': user.username, 'email': user.email, 'fullname': user.username } # the request succeeded: return provider_respond(server, openid_request, response, results) # the account is not active, so redirect back to the login page: request.session['openid_error'] = True msg = "Login failed - Account not active for user %s" AUDIT_LOG.warning(msg, username) return HttpResponseRedirect(openid_request_url) # determine consumer domain if applicable return_to = '' if 'openid.return_to' in request.REQUEST: return_to = request.REQUEST['openid.return_to'] matches = re.match(r'\w+:\/\/([\w\.-]+)', return_to) return_to = matches.group(1) # display login page response = render_to_response('provider_login.html', { 'error': error, 'return_to': return_to }) # add custom XRDS header necessary for discovery process response['X-XRDS-Location'] = get_xrds_url('xrds', request) return response
def openid_server(request): """ This view is the actual OpenID server - running at the URL pointed to by the <link rel="openid.server"> tag. """ logger.debug('server request %s: %s', request.method, request.POST or request.GET) server = Server(get_store(request), op_endpoint=request.build_absolute_uri( reverse('openid-provider-root'))) if not request.is_secure(): # if request is not secure allow only encrypted association sessions server.negotiator = encrypted_negotiator # Clear AuthorizationInfo session var, if it is set if request.session.get('AuthorizationInfo', None): del request.session['AuthorizationInfo'] querydict = dict(request.REQUEST.items()) orequest = server.decodeRequest(querydict) if not orequest: orequest = request.session.get('OPENID_REQUEST', None) if orequest: # remove session stored data: del request.session['OPENID_REQUEST'] else: # not request, render info page: data = { 'host': request.build_absolute_uri('/'), 'xrds_location': request.build_absolute_uri(reverse('openid-provider-xrds')), } logger.debug('invalid request, sending info: %s', data) return render_to_response('openid_provider/server.html', data, context_instance=RequestContext(request)) if orequest.mode in BROWSER_REQUEST_MODES: if not request.user.is_authenticated(): #return HttpResponse(orequest.return_to) logger.debug('no local authentication, sending landing page') return landing_page(request, orequest) openid = openid_is_authorized(request, orequest.identity, orequest.trust_root) if openid is not None: id_url = request.build_absolute_uri( reverse('openid-provider-identity', args=[openid.openid])) oresponse = orequest.answer(True, identity=id_url) logger.debug('orequest.answer(True, identity="%s")', id_url) elif orequest.immediate: logger.debug('checkid_immediate mode not supported') raise Exception('checkid_immediate mode not supported') else: request.session['OPENID_REQUEST'] = orequest logger.debug('redirecting to decide page') return HttpResponseRedirect(reverse('openid-provider-decide')) else: oresponse = server.handleRequest(orequest) if request.user.is_authenticated(): add_sreg_data(request, orequest, oresponse) if conf.AX_EXTENSION: add_ax_data(request, orequest, oresponse) # Convert a webresponse from the OpenID library in to a Django HttpResponse webresponse = server.encodeResponse(oresponse) if webresponse.code == 200 and orequest.mode in BROWSER_REQUEST_MODES: response = render_to_response('openid_provider/response.html', { 'body': webresponse.body, }, context_instance=RequestContext(request)) logger.debug('rendering browser response') else: response = HttpResponse(webresponse.body) response.status_code = webresponse.code for key, value in webresponse.headers.items(): response[key] = value logger.debug('rendering raw response') return response
def provider_login(request): """ OpenID login endpoint """ # make and validate endpoint endpoint = get_xrds_url("login", request) if not endpoint: return default_render_failure(request, "Invalid OpenID request") # initialize store and server store = DjangoOpenIDStore() server = Server(store, endpoint) # first check to see if the request is an OpenID request. # If so, the client will have specified an 'openid.mode' as part # of the request. querydict = dict(request.REQUEST.items()) error = False if "openid.mode" in request.GET or "openid.mode" in request.POST: # decode request try: openid_request = server.decodeRequest(querydict) except (UntrustedReturnURL, ProtocolError): openid_request = None if not openid_request: return default_render_failure(request, "Invalid OpenID request") # don't allow invalid and non-trusted trust roots if not validate_trust_root(openid_request): return default_render_failure(request, "Invalid OpenID trust root") # checkid_immediate not supported, require user interaction if openid_request.mode == "checkid_immediate": return provider_respond(server, openid_request, openid_request.answer(False), {}) # checkid_setup, so display login page # (by falling through to the provider_login at the # bottom of this method). elif openid_request.mode == "checkid_setup": if openid_request.idSelect(): # remember request and original path request.session["openid_setup"] = {"request": openid_request, "url": request.get_full_path()} # user failed login on previous attempt if "openid_error" in request.session: error = True del request.session["openid_error"] # OpenID response else: return provider_respond(server, openid_request, server.handleRequest(openid_request), {}) # handle login redirection: these are also sent to this view function, # but are distinguished by lacking the openid mode. We also know that # they are posts, because they come from the popup elif request.method == "POST" and "openid_setup" in request.session: # get OpenID request from session openid_setup = request.session["openid_setup"] openid_request = openid_setup["request"] openid_request_url = openid_setup["url"] del request.session["openid_setup"] # don't allow invalid trust roots if not validate_trust_root(openid_request): return default_render_failure(request, "Invalid OpenID trust root") # check if user with given email exists # Failure is redirected to this method (by using the original URL), # which will bring up the login dialog. email = request.POST.get("email", None) try: user = User.objects.get(email=email) except User.DoesNotExist: request.session["openid_error"] = True if settings.FEATURES["SQUELCH_PII_IN_LOGS"]: AUDIT_LOG.warning("OpenID login failed - Unknown user email") else: msg = "OpenID login failed - Unknown user email: {0}".format(email) AUDIT_LOG.warning(msg) return HttpResponseRedirect(openid_request_url) # attempt to authenticate user (but not actually log them in...) # Failure is again redirected to the login dialog. username = user.username password = request.POST.get("password", None) try: user = authenticate(username=username, password=password, request=request) except RateLimitException: AUDIT_LOG.warning("OpenID - Too many failed login attempts.") return HttpResponseRedirect(openid_request_url) if user is None: request.session["openid_error"] = True if settings.FEATURES["SQUELCH_PII_IN_LOGS"]: AUDIT_LOG.warning("OpenID login failed - invalid password") else: msg = "OpenID login failed - password for {0} is invalid".format(email) AUDIT_LOG.warning(msg) return HttpResponseRedirect(openid_request_url) # authentication succeeded, so fetch user information # that was requested if user is not None and user.is_active: # remove error from session since login succeeded if "openid_error" in request.session: del request.session["openid_error"] if settings.FEATURES["SQUELCH_PII_IN_LOGS"]: AUDIT_LOG.info("OpenID login success - user.id: {0}".format(user.id)) else: AUDIT_LOG.info("OpenID login success - {0} ({1})".format(user.username, user.email)) # redirect user to return_to location url = endpoint + urlquote(user.username) response = openid_request.answer(True, None, url) # Note too that this is hardcoded, and not really responding to # the extensions that were registered in the first place. results = {"nickname": user.username, "email": user.email, "fullname": user.profile.name} # the request succeeded: return provider_respond(server, openid_request, response, results) # the account is not active, so redirect back to the login page: request.session["openid_error"] = True if settings.FEATURES["SQUELCH_PII_IN_LOGS"]: AUDIT_LOG.warning("Login failed - Account not active for user.id {0}".format(user.id)) else: msg = "Login failed - Account not active for user {0}".format(username) AUDIT_LOG.warning(msg) return HttpResponseRedirect(openid_request_url) # determine consumer domain if applicable return_to = "" if "openid.return_to" in request.REQUEST: return_to = request.REQUEST["openid.return_to"] matches = re.match(r"\w+:\/\/([\w\.-]+)", return_to) return_to = matches.group(1) # display login page response = render_to_response("provider_login.html", {"error": error, "return_to": return_to}) # add custom XRDS header necessary for discovery process response["X-XRDS-Location"] = get_xrds_url("xrds", request) return response
def openid_server(request): """ This view is the actual OpenID server - running at the URL pointed to by the <link rel="openid.server"> tag. """ custom_log(request, "Server request: %s: %s" % (request.method, request.POST or request.GET), level="debug") server = Server(get_store(request), op_endpoint=request.build_absolute_uri(reverse('openid-provider-root'))) if not request.is_secure(): # if request is not secure allow only encrypted association sessions custom_log(request, "Request is not secure. Switching to encrypted negotiator", level="debug") server.negotiator = encrypted_negotiator # Clear AuthorizationInfo session var, if it is set if request.session.get('AuthorizationInfo', None): custom_log(request, "Clearing AuthorizationInfo session var", level="debug") del request.session['AuthorizationInfo'] querydict = dict(request.REQUEST.items()) orequest = server.decodeRequest(querydict) if not orequest: orequest = server.decodeRequest(request.session.get('OPENID_REQUEST', None)) if orequest: # remove session stored data: custom_log(request, "Removing stored data from session", level="debug") del request.session['OPENID_REQUEST'] else: # not request, render info page: data = { 'host': request.build_absolute_uri('/'), 'xrds_location': request.build_absolute_uri( reverse('openid-provider-xrds')), } custom_log(request, "Not an OpenID request, sending info: %s" % data, level="info") if request.browser and request.browser.user: data["openid_identifier"] = "https://" + request.get_host() + reverse('openid-provider-identity', args=[request.browser.user.username]) else: data["page_url"] = request.build_absolute_uri() return render_to_response('openid_provider/server.html', data, context_instance=RequestContext(request)) custom_log(request, "orequest.mode: %s" % orequest.mode, level="debug") if orequest.mode in BROWSER_REQUEST_MODES: if not (request.browser and request.browser.user and request.browser.is_authenticated() and request.user.is_authenticated()): custom_log(request, "no local authentication, sending landing page", level="debug") return landing_page(request, orequest) openid = openid_is_authorized(request, orequest.identity, orequest.trust_root) # verify return_to: trust_root_valid = trust_root_validation(orequest) custom_log(request, "trust_root_valid=%s" % trust_root_valid, level="debug") validated = False # Allow per-url exceptions for trust roots. for global_trusted_root in settings.OPENID_TRUSTED_ROOTS: if orequest.trust_root.startswith(global_trusted_root): custom_log(request, "Trust root %s is in always trusted roots. Set validated=True" % orequest.trust_root, level="debug") validated = True break if conf.FAILED_DISCOVERY_AS_VALID: if trust_root_valid == 'DISCOVERY_FAILED' or trust_root_valid == 'Unreachable': custom_log(request, "Setting validated=True as FAILED_DISCOVERY_AS_VALID is True", level="debug") validated = True else: # if in decide already took place, set as valid: if request.session.get(get_trust_session_key(orequest), False): custom_log(request, "Setting validated=True as session var %s is True" % (get_trust_session_key(orequest)), level="debug") validated = True custom_log(request, "Session key: %s=%s" % (get_trust_session_key(orequest), request.session.get(get_trust_session_key(orequest))), level="debug") custom_log(request, "OpenID is %s" % openid, level="debug") if openid is not None and (validated or trust_root_valid == 'Valid'): id_url = request.build_absolute_uri( reverse('openid-provider-identity', args=[openid.openid])) try: oresponse = orequest.answer(True, identity=id_url) except ValueError, e: return render_to_response("openid_provider/error.html", {"title": "Invalid identity URL", "msg": e.message}, context_instance=RequestContext(request)) custom_log(request, 'orequest.answer(True, identity="%s")' % id_url, level="debug") elif orequest.immediate: custom_log(request, 'checkid_immediate mode not supported', level="debug") raise Exception('checkid_immediate mode not supported') else: request.session['OPENID_REQUEST'] = orequest.message.toPostArgs() request.session['OPENID_TRUSTROOT_VALID'] = trust_root_valid custom_log(request, "redirecting to decide page", level="debug") return HttpResponseRedirect(reverse('openid-provider-decide'))
class StubOpenIDProvider(HTTPFetcher): def __init__(self, base_url): self.store = MemoryStore() self.identity_url = base_url + 'identity' self.localid_url = base_url + 'localid' self.endpoint_url = base_url + 'endpoint' self.server = Server(self.store, self.endpoint_url) self.last_request = None self.type_uris = ['http://specs.openid.net/auth/2.0/signon'] def fetch(self, url, body=None, headers=None): if url == self.identity_url: # Serve an XRDS document directly, pointing at our endpoint. type_uris = ['<Type>%s</Type>' % uri for uri in self.type_uris] return HTTPResponse( url, 200, {'content-type': 'application/xrds+xml'}, """\ <?xml version="1.0"?> <xrds:XRDS xmlns="xri://$xrd*($v*2.0)" xmlns:xrds="xri://$xrds"> <XRD> <Service priority="0"> %s <URI>%s</URI> <LocalID>%s</LocalID> </Service> </XRD> </xrds:XRDS> """ % ('\n'.join(type_uris), self.endpoint_url, self.localid_url)) elif url.startswith(self.endpoint_url): # Gather query parameters query = {} if '?' in url: query.update(cgi.parse_qsl(url.split('?', 1)[1])) if body is not None: query.update(cgi.parse_qsl(body)) self.last_request = self.server.decodeRequest(query) # The browser based requests should not be handled through # the fetcher interface. assert self.last_request.mode not in BROWSER_REQUEST_MODES response = self.server.handleRequest(self.last_request) webresponse = self.server.encodeResponse(response) return HTTPResponse(url, webresponse.code, webresponse.headers, webresponse.body) else: raise HTTPFetchingError('unknown URL %s' % url) def parseFormPost(self, content): """Parse an HTML form post to create an OpenID request.""" # Hack to make the javascript XML compliant ... content = content.replace('i < elements.length', 'i < elements.length') tree = ET.XML(content) form = tree.find('.//form') assert form is not None, 'No form in document' assert form.get('action') == self.endpoint_url, ( 'Form posts to %s instead of %s' % (form.get('action'), self.endpoint_url)) query = {} for input in form.findall('input'): if input.get('type') != 'hidden': continue query[input.get('name').encode('UTF-8')] = \ input.get('value').encode('UTF-8') self.last_request = self.server.decodeRequest(query) return self.last_request
class OpenIDMixin: """A mixin with OpenID helper methods.""" openid_request = None def __init__(self, context, request): super(OpenIDMixin, self).__init__(context, request) self.server_url = get_server_url() self.openid_server = Server(openid_store, self.server_url) @property def user_identity_url(self): return ITestOpenIDPersistentIdentity(self.account).openid_identity_url def isIdentityOwner(self): """Return True if the user can authenticate as the given ID.""" assert self.account is not None, "user should be logged in by now." return (self.openid_request.idSelect() or self.openid_request.identity == self.user_identity_url) @cachedproperty def openid_parameters(self): """A dictionary of OpenID query parameters from request.""" query = {} for key, value in self.request.form.items(): if key.startswith('openid.'): # All OpenID query args are supposed to be ASCII. query[key.encode('US-ASCII')] = value.encode('US-ASCII') return query def getSession(self): """Get the session data container that stores the OpenID request.""" if IUnauthenticatedPrincipal.providedBy(self.request.principal): # A dance to assert that we want to break the rules about no # unauthenticated sessions. Only after this next line is it # safe to set session values. allowUnauthenticatedSession( self.request, duration=timedelta(minutes=60)) return ISession(self.request)[SESSION_PKG_KEY] def restoreRequestFromSession(self): """Get the OpenIDRequest from our session.""" session = self.getSession() cache = get_property_cache(self) try: cache.openid_parameters = session[OPENID_REQUEST_SESSION_KEY] except KeyError: raise UnexpectedFormData("No OpenID request in session") # Decode the request parameters and create the request object. self.openid_request = self.openid_server.decodeRequest( self.openid_parameters) assert zisinstance(self.openid_request, CheckIDRequest), ( 'Invalid OpenIDRequest in session') def saveRequestInSession(self): """Save the OpenIDRequest in our session.""" query = self.openid_parameters assert query.get('openid.mode') == 'checkid_setup', ( 'Can only serialise checkid_setup OpenID requests') session = self.getSession() # If this was meant for use in production we'd have to use a nonce # as the key when storing the openid request in the session, but as # it's meant to run only on development instances we can simplify # things a bit by storing the openid request using a well known key. session[OPENID_REQUEST_SESSION_KEY] = query def renderOpenIDResponse(self, openid_response): """Return a web-suitable response constructed from openid_response.""" webresponse = self.openid_server.encodeResponse(openid_response) response = self.request.response response.setStatus(webresponse.code) # encodeResponse doesn't generate a content-type, help it out if (webresponse.code == 200 and webresponse.body and openid_response.whichEncoding() == ENCODE_HTML_FORM): response.setHeader('content-type', 'text/html') for header, value in webresponse.headers.items(): response.setHeader(header, value) return webresponse.body def createPositiveResponse(self): """Create a positive assertion OpenIDResponse. This method should be called to create the response to successful checkid requests. If the trust root for the request is in openid_sreg_trustroots, then additional user information is included with the response. """ assert self.account is not None, ( 'Must be logged in for positive OpenID response') assert self.openid_request is not None, ( 'No OpenID request to respond to.') if not self.isIdentityOwner(): return self.createFailedResponse() if self.openid_request.idSelect(): response = self.openid_request.answer( True, identity=self.user_identity_url) else: response = self.openid_request.answer(True) person = IPerson(self.account) sreg_fields = dict( nickname=person.name, email=person.preferredemail.email, fullname=self.account.displayname) sreg_request = SRegRequest.fromOpenIDRequest(self.openid_request) sreg_response = SRegResponse.extractResponse( sreg_request, sreg_fields) response.addExtension(sreg_response) return response def createFailedResponse(self): """Create a failed assertion OpenIDResponse. This method should be called to create the response to unsuccessful checkid requests. """ assert self.openid_request is not None, ( 'No OpenID request to respond to.') response = self.openid_request.answer(False, self.server_url) return response
def provider_login(request): """ OpenID login endpoint """ # pylint: disable=too-many-statements # make and validate endpoint endpoint = get_xrds_url('login', request) if not endpoint: return default_render_failure(request, "Invalid OpenID request") # initialize store and server store = DjangoOpenIDStore() server = Server(store, endpoint) # first check to see if the request is an OpenID request. # If so, the client will have specified an 'openid.mode' as part # of the request. if request.method == 'GET': querydict = dict(request.GET.items()) else: querydict = dict(request.POST.items()) error = False if 'openid.mode' in request.GET or 'openid.mode' in request.POST: # decode request try: openid_request = server.decodeRequest(querydict) except (UntrustedReturnURL, ProtocolError): openid_request = None if not openid_request: return default_render_failure(request, "Invalid OpenID request") # don't allow invalid and non-trusted trust roots if not validate_trust_root(openid_request): return default_render_failure(request, "Invalid OpenID trust root") # checkid_immediate not supported, require user interaction if openid_request.mode == 'checkid_immediate': return provider_respond(server, openid_request, openid_request.answer(False), {}) # checkid_setup, so display login page # (by falling through to the provider_login at the # bottom of this method). elif openid_request.mode == 'checkid_setup': if openid_request.idSelect(): # remember request and original path request.session['openid_setup'] = { 'request': openid_request, 'url': request.get_full_path(), 'post_params': request.POST, } # user failed login on previous attempt if 'openid_error' in request.session: error = True del request.session['openid_error'] # OpenID response else: return provider_respond(server, openid_request, server.handleRequest(openid_request), {}) # handle login redirection: these are also sent to this view function, # but are distinguished by lacking the openid mode. We also know that # they are posts, because they come from the popup elif request.method == 'POST' and 'openid_setup' in request.session: # get OpenID request from session openid_setup = request.session['openid_setup'] openid_request = openid_setup['request'] openid_request_url = openid_setup['url'] post_params = openid_setup['post_params'] # We need to preserve the parameters, and the easiest way to do this is # through the URL url_post_params = { param: post_params[param] for param in post_params if param.startswith('openid') } encoded_params = urllib.urlencode(url_post_params) if '?' not in openid_request_url: openid_request_url = openid_request_url + '?' + encoded_params else: openid_request_url = openid_request_url + '&' + encoded_params del request.session['openid_setup'] # don't allow invalid trust roots if not validate_trust_root(openid_request): return default_render_failure(request, "Invalid OpenID trust root") # check if user with given email exists # Failure is redirected to this method (by using the original URL), # which will bring up the login dialog. email = request.POST.get('email', None) try: user = User.objects.get(email=email) except User.DoesNotExist: request.session['openid_error'] = True if settings.FEATURES['SQUELCH_PII_IN_LOGS']: AUDIT_LOG.warning(u"OpenID login failed - Unknown user email") else: msg = u"OpenID login failed - Unknown user email: {0}".format(email) AUDIT_LOG.warning(msg) return HttpResponseRedirect(openid_request_url) # attempt to authenticate user (but not actually log them in...) # Failure is again redirected to the login dialog. username = user.username password = request.POST.get('password', None) try: user = authenticate(username=username, password=password, request=request) except RateLimitException: AUDIT_LOG.warning(u'OpenID - Too many failed login attempts.') return HttpResponseRedirect(openid_request_url) if user is None: request.session['openid_error'] = True if settings.FEATURES['SQUELCH_PII_IN_LOGS']: AUDIT_LOG.warning(u"OpenID login failed - invalid password") else: AUDIT_LOG.warning( u"OpenID login failed - password for %s is invalid", email) return HttpResponseRedirect(openid_request_url) # authentication succeeded, so fetch user information # that was requested if user is not None and user.is_active: # remove error from session since login succeeded if 'openid_error' in request.session: del request.session['openid_error'] if settings.FEATURES['SQUELCH_PII_IN_LOGS']: AUDIT_LOG.info(u"OpenID login success - user.id: %s", user.id) else: AUDIT_LOG.info( u"OpenID login success - %s (%s)", user.username, user.email) # redirect user to return_to location url = endpoint + urlquote(user.username) response = openid_request.answer(True, None, url) # Note too that this is hardcoded, and not really responding to # the extensions that were registered in the first place. results = { 'nickname': user.username, 'email': user.email, 'fullname': user.profile.name, } # the request succeeded: return provider_respond(server, openid_request, response, results) # the account is not active, so redirect back to the login page: request.session['openid_error'] = True if settings.FEATURES['SQUELCH_PII_IN_LOGS']: AUDIT_LOG.warning( u"Login failed - Account not active for user.id %s", user.id) else: AUDIT_LOG.warning( u"Login failed - Account not active for user %s", username) return HttpResponseRedirect(openid_request_url) # determine consumer domain if applicable return_to = request.GET.get('openid.return_to') or request.POST.get('openid.return_to') or '' if return_to: matches = re.match(r'\w+:\/\/([\w\.-]+)', return_to) return_to = matches.group(1) # display login page response = render_to_response('provider_login.html', { 'error': error, 'return_to': return_to }) # add custom XRDS header necessary for discovery process response['X-XRDS-Location'] = get_xrds_url('xrds', request) return response
def openid_server(request): """ This view is the actual OpenID server - running at the URL pointed to by the <link rel="openid.server"> tag. """ logger.debug('server request %s: %s', request.method, request.POST or request.GET) server = Server(get_store(request), op_endpoint=request.build_absolute_uri(reverse('openid-provider-root'))) if not request.is_secure(): # if request is not secure allow only encrypted association sessions server.negotiator = encrypted_negotiator # Clear AuthorizationInfo session var, if it is set if request.session.get('AuthorizationInfo', None): del request.session['AuthorizationInfo'] querydict = dict(request.POST.items()) orequest = server.decodeRequest(querydict) if not orequest: orequest = request.session.get('OPENID_REQUEST', None) if orequest: # remove session stored data: del request.session['OPENID_REQUEST'] else: # not request, render info page: data = { 'host': request.build_absolute_uri('/'), 'xrds_location': request.build_absolute_uri( reverse('openid-provider-xrds')), } # Return empty string return HttpResponse("", content_type="text/plain") if orequest.mode in BROWSER_REQUEST_MODES: if not request.user.is_authenticated: logger.debug('no local authentication, sending landing page') return landing_page(request, orequest) openid = openid_is_authorized(request, orequest.identity, orequest.trust_root) if openid is not None: id_url = request.build_absolute_uri( reverse('openid-provider-identity', args=[openid.openid])) oresponse = orequest.answer(True, identity=id_url) logger.debug('orequest.answer(True, identity="%s")', id_url) elif orequest.immediate: logger.debug('checkid_immediate mode not supported') raise Exception('checkid_immediate mode not supported') else: request.session['OPENID_REQUEST'] = orequest logger.debug('redirecting to decide page') return HttpResponseRedirect(reverse('openid-provider-decide')) else: oresponse = server.handleRequest(orequest) if request.user.is_authenticated: add_sreg_data(request, orequest, oresponse) if conf.AX_EXTENSION: add_ax_data(request, orequest, oresponse) # Convert a webresponse from the OpenID library in to a Django HttpResponse webresponse = server.encodeResponse(oresponse) if webresponse.code == 200 and orequest.mode in BROWSER_REQUEST_MODES: response = render(request, 'openid_provider/response.html', { 'body': webresponse.body, }) logger.debug('rendering browser response') else: response = HttpResponse(webresponse.body) response.status_code = webresponse.code for key, value in webresponse.headers.items(): response[key] = value logger.debug('rendering raw response') return response
def get_server(self, request): url = request.build_absolute_uri(request.path) return Server(DjangoOpenIDStore(), op_endpoint=url)
class OpenIDProvider(object): # OpenID service type URIs, listed in order of preference. The # ordering of this list affects yadis and XRI service discovery. openid_type_uris = [ #discover.OPENID_IDP_2_0_TYPE, discover.OPENID_2_0_TYPE, discover.OPENID_1_1_TYPE, discover.OPENID_1_0_TYPE, sreg.ns_uri, ] def __init__(self, request): self.request = request self.openid_server = Server(SFOpenIDStore(self.request.db_session), request.route_url('openid_provider')) userid = authenticated_userid(request) self.auth_userid = userid or request.session.get('auth_userid') if self.auth_userid: query = self.request.db_session.query(UserProfile) self.auth_user = query.get(self.auth_userid) else: self.auth_user = None def process(self, request_params): logger.debug('Processing openid request: %s', request_params) if request_params.get('openid.identity'): home_url = self.request.route_url('home') if request_params['openid.identity'] == request_params['openid.claimed_id'] and \ request_params['openid.identity'] == home_url: username = self.request.user and self.request.user.username or \ self.auth_userid if username: username = username.lower() user_url = self.request.route_url('user_profile', username=username) request_params['openid.identity'] = user_url request_params['openid.claimed_id'] = user_url try: openid_request = self.openid_server.decodeRequest(request_params) # MalformedReturnURL, UntrustedReturnURL, etc. except ProtocolError as e: logger.info( 'Unable to decode request: %s %s', e.__class__, e.openid_message ) return '' logger.debug('Decoded request: %s', openid_request) if openid_request is None: return '' if openid_request.mode in ["checkid_immediate", "checkid_setup"]: if self.request.user or self.auth_userid: openid_response = self.handleCheckIDRequest(openid_request) else: # If the user has not logged in yet, stash the OpenID # consuming site request (if there isn't one already) and # send them to the login view. The openid_tween will take # care of sending them back to the OpenID consuming site. rp_dict = dict(request_params.items()) self.request.session['openid_request'] = rp_dict self.request.session.save() return HTTPFound(location=self.request.route_url('login')) else: openid_response = self.openid_server.handleRequest(openid_request) logger.debug('Decoded response: %s', openid_response) encoded_response = self.openid_server.encodeResponse(openid_response) if 'location' in encoded_response.headers: response = HTTPFound(location=encoded_response.headers['location']) return response return encoded_response.body def get(self): return self.process(self.request.GET) def post(self): if self.request.method != "POST": return HTTPMethodNotAllowed() return self.process(self.request.POST) def approved(self, request, identifier=None): response = request.answer(True, identity=identifier) self.addSRegResponse(request, response) return response def handleCheckIDRequest(self, request): is_authorized = self.isAuthorized(request.identity, request.trust_root) if is_authorized: return self.approved(request, request.identity) else: return request.answer(False, identity=request.identity) def isAuthorized(self, identity_url, trust_root): if not self.auth_userid: return False self.request.registry.notify(CheckIDAuthorized(self.request, self.auth_user)) # TODO: prompt user for authorization return True def addSRegResponse(self, request, response): sreg_req = sreg.SRegRequest.fromOpenIDRequest(request) sreg_data = dict([ (fname, None) for fname in sreg.data_fields ]) sreg_data['fullname'] = '%s %s' % (self.auth_user.first_name, self.auth_user.last_name) sreg_data['nickname'] = self.auth_userid sreg_data['email'] = self.auth_user.email sreg_resp = sreg.SRegResponse.extractResponse(sreg_req, sreg_data) response.addExtension(sreg_resp) def identity(self): query = self.request.db_session.query(UserProfile) target_username = self.request.matchdict['username'] target_user = query.get(target_username) if target_user is None: raise HTTPNotFound() return { 'username': target_user.username.lower(), }
def __init__(self): from openid.server.server import Server from openid.store.memstore import MemoryStore store = MemoryStore() self.server = Server(store, 'http://www.jaraco.com/')
def provider_login(request): """ OpenID login endpoint """ # make and validate endpoint endpoint = get_xrds_url('login', request) if not endpoint: return default_render_failure(request, "Invalid OpenID request") # initialize store and server store = DjangoOpenIDStore() server = Server(store, endpoint) # first check to see if the request is an OpenID request. # If so, the client will have specified an 'openid.mode' as part # of the request. if request.method == 'GET': querydict = dict(request.GET.items()) else: querydict = dict(request.POST.items()) error = False if 'openid.mode' in request.GET or 'openid.mode' in request.POST: # decode request try: openid_request = server.decodeRequest(querydict) except (UntrustedReturnURL, ProtocolError): openid_request = None if not openid_request: return default_render_failure(request, "Invalid OpenID request") # don't allow invalid and non-trusted trust roots if not validate_trust_root(openid_request): return default_render_failure(request, "Invalid OpenID trust root") # checkid_immediate not supported, require user interaction if openid_request.mode == 'checkid_immediate': return provider_respond(server, openid_request, openid_request.answer(False), {}) # checkid_setup, so display login page # (by falling through to the provider_login at the # bottom of this method). elif openid_request.mode == 'checkid_setup': if openid_request.idSelect(): # remember request and original path request.session['openid_setup'] = { 'request': openid_request, 'url': request.get_full_path(), 'post_params': request.POST, } # user failed login on previous attempt if 'openid_error' in request.session: error = True del request.session['openid_error'] # OpenID response else: return provider_respond(server, openid_request, server.handleRequest(openid_request), {}) # handle login redirection: these are also sent to this view function, # but are distinguished by lacking the openid mode. We also know that # they are posts, because they come from the popup elif request.method == 'POST' and 'openid_setup' in request.session: # get OpenID request from session openid_setup = request.session['openid_setup'] openid_request = openid_setup['request'] openid_request_url = openid_setup['url'] post_params = openid_setup['post_params'] # We need to preserve the parameters, and the easiest way to do this is # through the URL url_post_params = { param: post_params[param] for param in post_params if param.startswith('openid') } encoded_params = urllib.urlencode(url_post_params) if '?' not in openid_request_url: openid_request_url = openid_request_url + '?' + encoded_params else: openid_request_url = openid_request_url + '&' + encoded_params del request.session['openid_setup'] # don't allow invalid trust roots if not validate_trust_root(openid_request): return default_render_failure(request, "Invalid OpenID trust root") # check if user with given email exists # Failure is redirected to this method (by using the original URL), # which will bring up the login dialog. email = request.POST.get('email', None) try: user = User.objects.get(email=email) except User.DoesNotExist: request.session['openid_error'] = True if settings.FEATURES['SQUELCH_PII_IN_LOGS']: AUDIT_LOG.warning(u"OpenID login failed - Unknown user email") else: msg = u"OpenID login failed - Unknown user email: {0}".format(email) AUDIT_LOG.warning(msg) return HttpResponseRedirect(openid_request_url) # attempt to authenticate user (but not actually log them in...) # Failure is again redirected to the login dialog. username = user.username password = request.POST.get('password', None) try: user = authenticate(username=username, password=password, request=request) except RateLimitException: AUDIT_LOG.warning(u'OpenID - Too many failed login attempts.') return HttpResponseRedirect(openid_request_url) if user is None: request.session['openid_error'] = True if settings.FEATURES['SQUELCH_PII_IN_LOGS']: AUDIT_LOG.warning(u"OpenID login failed - invalid password") else: AUDIT_LOG.warning( u"OpenID login failed - password for %s is invalid", email) return HttpResponseRedirect(openid_request_url) # authentication succeeded, so fetch user information # that was requested if user is not None and user.is_active: # remove error from session since login succeeded if 'openid_error' in request.session: del request.session['openid_error'] if settings.FEATURES['SQUELCH_PII_IN_LOGS']: AUDIT_LOG.info(u"OpenID login success - user.id: %s", user.id) else: AUDIT_LOG.info( u"OpenID login success - %s (%s)", user.username, user.email) # redirect user to return_to location url = endpoint + urlquote(user.username) response = openid_request.answer(True, None, url) # Note too that this is hardcoded, and not really responding to # the extensions that were registered in the first place. results = { 'nickname': user.username, 'email': user.email, 'fullname': user.profile.name, } # the request succeeded: return provider_respond(server, openid_request, response, results) # the account is not active, so redirect back to the login page: request.session['openid_error'] = True if settings.FEATURES['SQUELCH_PII_IN_LOGS']: AUDIT_LOG.warning( u"Login failed - Account not active for user.id %s", user.id) else: AUDIT_LOG.warning( u"Login failed - Account not active for user %s", username) return HttpResponseRedirect(openid_request_url) # determine consumer domain if applicable return_to = request.GET.get('openid.return_to') or request.POST.get('openid.return_to') or '' if return_to: matches = re.match(r'\w+:\/\/([\w\.-]+)', return_to) return_to = matches.group(1) # display login page response = render_to_response('provider_login.html', { 'error': error, 'return_to': return_to }) # add custom XRDS header necessary for discovery process response['X-XRDS-Location'] = get_xrds_url('xrds', request) return response