def done(res): res = json.loads(res) try: if res['status'] == 'okay': # awesome: Mozilla Persona successfully authenticated the user self._transport._authid = res['email'] self._transport._authrole = self._pending_auth.role self._transport._authmethod = 'mozilla_persona' log.msg("Authenticated user {} with role {}".format(self._transport._authid, self._transport._authrole)) dres.callback(types.Accept(authid=self._transport._authid, authrole=self._transport._authrole, authmethod=self._transport._authmethod)) # remember the user's auth info (this marks the cookie as authenticated) if self._transport._cbtid and self._transport.factory._cookiestore: cs = self._transport.factory._cookiestore cs.setAuth(self._transport._cbtid, self._transport._authid, self._transport._authrole, self._transport._authmethod) # kick all sessions using same cookie (but not _this_ connection) if True: for proto in cs.getProtos(self._transport._cbtid): if proto and proto != self._transport: try: proto.close() except Exception as e: pass else: log.msg("Authentication failed!") log.msg(res) dres.callback(types.Deny(reason="wamp.error.authorization_failed", message=res.get("reason", None))) except Exception as e: log.msg("internal error during authentication verification: {}".format(e)) dres.callback(types.Deny(reason="wamp.error.internal_error", message=str(e)))
def _accept(self): return types.Accept(realm=self._realm, authid=self._authid, authrole=self._authrole, authmethod=self._authmethod, authprovider=self._authprovider, authextra=self._authextra)
def onAuthenticate(self, router_session, signature, extra): try: challenge = router_session.challenge authid = challenge["authid"] if challenge == None: return if router_session.challenge.get("authmethod") != u"cookie": return for field in ["authrole", "authmethod", "authprovider"]: if field not in challenge: # Challenge not in expected format. It was probably # created by another plugin. return except Exception as e: # let another plugin handle this return cookie = self.cookies.get(authid) if cookie != signature: log("Failed cookie login for %s." % challenge["authid"]) return types.Deny(message=u"Invalid cookie.") log("Successful cookie login for %s." % challenge["authid"]) return types.Accept(authid=challenge["authid"], authrole=challenge["authrole"], authmethod=challenge["authmethod"], authprovider=challenge["authprovider"])
def onHello(self, realm, details): print "onHello: {} {}".format(realm, details) if self._transport._authenticated is not None: return types.Accept(authid=self._transport._authenticated) else: return types.Challenge("mozilla-persona") return accept
def onAuthenticate(self, signature, extra): """ Callback fired when a client responds to an authentication challenge. """ print("onAuthenticate: {} {}".format(signature, extra)) # if there is a pending auth, and the signature provided by client matches .. if self._pending_auth: if signature == self._pending_auth.signature: # accept the client return types.Accept( authid=self._pending_auth.authid, authrole=self._pending_auth.authrole, authmethod=self._pending_auth.authmethod, authprovider=self._pending_auth.authprovider) else: # deny client return types.Deny(message=u"signature is invalid") else: # deny client return types.Deny(message=u"no pending authentication")
def onHello(self, realm, details): """On receiving a hello, issue a Challenge to the client""" if getattr(self._transport, '_authenticated', None) is not None: return types.Accept(authid=self._transport._authenticated) else: return types.Challenge('userpass', { 'timestamp': time.time(), })
def on_success(response): content = json.loads(response) if content.get('success'): username = content.get('username') if username: return types.Accept(content['username']) log.msg('Rejected login: %s' % (content, )) return types.Deny()
def onHello(self, router_session, realm, details): for authmethod in details.authmethods: if authmethod == u"anonymous": log("Successful anonymous login (ID: %s)." % \ details.pending_session) return types.Accept(authid=u"anonymous", authrole=u"anonymous", authmethod=u"anonymous", authprovider=u"anonymous")
def onHello(self, realm, details): """ Callback fired when client wants to attach session. """ print("MyRouterSession.onHello: {} {}".format(realm, details)) for authmethod in details.authmethods: if authmethod == u"cookie" and self._transport._authenticated is not None: # already authenticated via Cookie on transport return types.Accept(authid=self._transport._authenticated, authrole="user", authmethod="cookie") elif authmethod == u"mozilla-persona": # not yet authenticated: send challenge return types.Challenge("mozilla-persona") return types.Deny()
def onAuthenticate(self, router_session, signature, extra): try: challenge = router_session.challenge if challenge == None: return if router_session.challenge.get("authmethod") != u"wampcra": return for field in ["authid", "authrole", "authmethod", "authprovider"]: if field not in challenge: # Challenge not in expected format. It was probably # created by another plugin. return if not router_session.challenge or not router_session.signature: log("Failed wampcra login for %s." % challenge["authid"]) return types.Deny(message=u"No pending authentication.") if len(signature) != len(router_session.signature): log("Failed wampcra login for %s." % challenge["authid"]) return types.Deny(message=u"Invalid signature.") success = True # Check each character to prevent HMAC timing attacks. This is # really not an issue since each challenge gets a new nonce, # but better safe than sorry. for i in range(len(router_session.signature)): if signature[i] != router_session.signature[i]: success = False # Reject the user if we did not actually find them in the database. if not router_session.exists: log("User %s not found." % challenge["authid"]) success = False if success: log("Successful wampcra login for %s." % challenge["authid"]) return types.Accept(authid=challenge["authid"], authrole=challenge["authrole"], authmethod=challenge["authmethod"], authprovider=challenge["authprovider"]) log("Failed wampcra login for %s." % challenge["authid"]) return types.Deny(message=u"Invalid signature.") except: # let another plugin handle this return
def on_authenticate_ok(principal): if isinstance(principal, dict): # dynamic ticket authenticator returned a dictionary (new) authid = principal.get("authid", self._pending_auth.authid) authrole = principal["role"] else: # backwards compatibility: dynamic ticket authenticator # was expected to return a role directly authid = self._pending_auth.authid authrole = principal return types.Accept(authid=authid, authrole=authrole, authmethod=self._pending_auth.authmethod, authprovider=self._pending_auth.authprovider)
def done(res): res = json.loads(res) try: if res['status'] == 'okay': # Mozilla Persona successfully authenticated the user # remember the user's email address. this marks the cookie as # authenticated self._transport.factory._cookies[self._transport._cbtid]['authenticated'] = res['email'] log.msg("Authenticated user {}".format(res['email'])) dres.callback(types.Accept(authid=res['email'], authrole="user", authmethod="mozilla-persona")) else: log.msg("Authentication failed!") dres.callback(types.Deny()) except Exception as e: print "ERRR", e
def onHello(self, realm, details): print("On hello: {}".format(details)) if u"exodoc-ticket" not in details.authmethods: return types.Deny( u"wamp.error.not_authorized", message=u"Only 'exodoc-ticket' supported as authmethods") if not details.authid.startswith("good-ticket-"): return types.Deny(u"wamp.error.not_authorized", message=u"Bad credential") self._authid = details.authid[len("good-ticket-"):] self._authmethod = u"exodoc-ticket" self._authrole = u"chatter" self._authprovider = u"redis-token" return types.Accept( authid=self._authid, authrole=self._authrole, authmethod=self._authmethod, authprovider=self._authprovider, )
def onAuthenticate(self, signature, extra): """ Callback fired when a client responds to an authentication challenge. """ print("onAuthenticate: {} {}".format(signature, extra)) ## if there is a pending auth, and the signature provided by client matches .. if self._pending_auth: if signature == auth.compute_totp(self._pending_auth.secret) or \ signature == auth.compute_totp(self._pending_auth.secret, 1) or \ signature == auth.compute_totp(self._pending_auth.secret, -1): ## accept the client return types.Accept( authid=self._pending_auth.authid, authrole=self._pending_auth.authrole, authmethod=self._pending_auth.authmethod, authprovider=self._pending_auth.authprovider) ## deny client return types.Deny()
def onHello(self, realm, details): try: # default authentication method is "WAMP-Anonymous" if client doesn't specify otherwise authmethods = details.authmethods or [u'anonymous'] # if the client had a reassigned realm during authentication, restore it from the cookie if hasattr(self._transport, '_authrealm') and self._transport._authrealm: realm = self._transport._authrealm # perform authentication if self._transport._authid is not None and ( self._transport._authmethod == u'trusted' or self._transport._authprovider in authmethods): # already authenticated .. e.g. via HTTP Cookie or TLS client-certificate # check if role still exists on realm allow = self._router_factory[realm].has_role( self._transport._authrole) if allow: return types.Accept( realm=realm, authid=self._transport._authid, authrole=self._transport._authrole, authmethod=self._transport._authmethod, authprovider=self._transport._authprovider, authextra=None) else: return types.Deny( ApplicationError.NO_SUCH_ROLE, message= "session was previously authenticated (via transport), but role '{}' no longer exists on realm '{}'" .format(self._transport._authrole, realm)) else: auth_config = self._transport_config.get(u'auth', None) if not auth_config: # if authentication is _not_ configured, allow anyone to join as "anonymous"! # .. but don't if the client isn't ready/willing to go on "anonymous" if u'anonymous' not in authmethods: return types.Deny( ApplicationError.NO_AUTH_METHOD, message= u'cannot authenticate using any of the offered authmethods {}' .format(authmethods)) if not realm: return types.Deny(ApplicationError.NO_SUCH_REALM, message=u'no realm requested') if realm not in self._router_factory: return types.Deny( ApplicationError.NO_SUCH_REALM, message=u'no realm "{}" exists on this router'. format(realm)) # we ignore any details.authid the client might have announced, and use # a cookie value or a random value if hasattr(self._transport, "_cbtid") and self._transport._cbtid: # if cookie tracking is enabled, set authid to cookie value authid = self._transport._cbtid else: # if no cookie tracking, generate a random value for authid authid = util.generate_serial_number() return types.Accept(realm=realm, authid=authid, authrole=u'anonymous', authmethod=u'anonymous', authprovider=u'static', authextra=None) else: # iterate over authentication methods announced by client .. for authmethod in authmethods: # invalid authmethod if authmethod not in AUTHMETHODS: return types.Deny( message=u'invalid authmethod "{}"'.format( authmethod)) # authmethod not configured if authmethod not in auth_config: self.log.debug( "client requested valid, but unconfigured authentication method {authmethod}", authmethod=authmethod) continue # authmethod not available if authmethod not in AUTHMETHOD_MAP: self.log.debug( "client requested valid, but unavailable authentication method {authmethod}", authmethod=authmethod) continue # WAMP-Anonymous, WAMP-Ticket, WAMP-CRA, WAMP-TLS, WAMP-Cryptosign if authmethod in [ u'anonymous', u'ticket', u'wampcra', u'tls', u'cryptosign' ]: PendingAuthKlass = AUTHMETHOD_MAP[authmethod] self._pending_auth = PendingAuthKlass( self, auth_config[authmethod]) return self._pending_auth.hello(realm, details) # WAMP-Cookie authentication elif authmethod == u'cookie': # the client requested cookie authentication, but there is 1) no cookie set, # or 2) a cookie set, but that cookie wasn't authenticated before using # a different auth method (if it had been, we would never have entered here, since then # auth info would already have been extracted from the transport) # consequently, we skip this auth method and move on to next auth method. continue else: # should not arrive here raise Exception("logic error") # no suitable authmethod found! return types.Deny( ApplicationError.NO_AUTH_METHOD, message= u'cannot authenticate using any of the offered authmethods {}' .format(authmethods)) except Exception as e: self.log.failure('internal error: {log_failure.value}') self.log.critical("internal error: {msg}", msg=str(e)) return types.Deny(message=u'internal error: {}'.format(e))
def onAuthenticate(self, signature, extra): """ Callback fired when a client responds to an authentication challenge. """ print("onAuthenticate: {} {}".format(signature, extra)) # if there is a pending auth, check the challenge response. The specifics # of how to check depend on the authentication method # if self._pending_auth: # WAMP-CRA # if isinstance(self._pending_auth, PendingAuthWampCra): if signature == self._pending_auth.signature: # WAMP-CRA authentication signature was valid: accept the client # return types.Accept( authid=self._pending_auth.authid, authrole=self._pending_auth.authrole, authmethod=self._pending_auth.authmethod, authprovider=self._pending_auth.authprovider) else: # WAMP-CRA authentication signature was invalid: deny client # return types.Deny(message=u"signature is invalid") # WAMP-Ticket # elif isinstance(self._pending_auth, PendingAuthTicket): # when doing WAMP-Ticket from static configuration, the ticket we # expect was store on the pending authentication object and we just compare .. # if self._pending_auth.authprovider == 'static': if signature == self._pending_auth.ticket: # WAMP-Ticket authentication ticket was valid: accept the client # return types.Accept( authid=self._pending_auth.authid, authrole=self._pending_auth.authrole, authmethod=self._pending_auth.authmethod, authprovider=self._pending_auth.authprovider) else: # WAMP-Ticket authentication ticket was invalid: deny client # return types.Deny(message=u"ticket is invalid") # WAMP-Ticket dynamic .. # else: # call the configured dynamic authenticator procedure # via the router's service session # service_session = self._router_factory.get( self._pending_auth.realm)._realm.session d = service_session.call(self._pending_auth.authprovider, self._pending_auth.realm, self._pending_auth.authid, signature) def on_authenticate_ok(principal): if isinstance(principal, dict): # dynamic ticket authenticator returned a dictionary (new) authid = principal.get("authid", self._pending_auth.authid) authrole = principal["role"] else: # backwards compatibility: dynamic ticket authenticator # was expected to return a role directly authid = self._pending_auth.authid authrole = principal return types.Accept( authid=authid, authrole=authrole, authmethod=self._pending_auth.authmethod, authprovider=self._pending_auth.authprovider) def on_authenticate_error(err): error = None message = "dynamic WAMP-Ticket credential getter failed: {}".format( err) if isinstance(err.value, ApplicationError): error = err.value.error if err.value.args and len(err.value.args): message = err.value.args[0] return types.Deny(error, message) d.addCallbacks(on_authenticate_ok, on_authenticate_error) return d elif isinstance(self._pending_auth, PendingAuthPersona): dres = Deferred() # The client did it's Mozilla Persona authentication thing # and now wants to verify the authentication and login. assertion = signature audience = str(self._pending_auth.audience ) # eg "http://192.168.1.130:8080/" provider = str( self._pending_auth.provider ) # eg "https://verifier.login.persona.org/verify" # To verify the authentication, we need to send a HTTP/POST # to Mozilla Persona. When successful, Persona will send us # back something like: # { # "audience": "http://192.168.1.130:8080/", # "expires": 1393681951257, # "issuer": "gmail.login.persona.org", # "email": "*****@*****.**", # "status": "okay" # } headers = {'Content-Type': 'application/x-www-form-urlencoded'} body = urllib.urlencode({ 'audience': audience, 'assertion': assertion }) from twisted.web.client import getPage d = getPage(url=provider, method='POST', postdata=body, headers=headers) self.log.info("Authentication request sent.") def done(res): res = json.loads(res) try: if res['status'] == 'okay': # awesome: Mozilla Persona successfully authenticated the user self._transport._authid = res['email'] self._transport._authrole = self._pending_auth.role self._transport._authmethod = 'mozilla_persona' self.log.info( "Authenticated user {} with role {}".format( self._transport._authid, self._transport._authrole)) dres.callback( types.Accept( authid=self._transport._authid, authrole=self._transport._authrole, authmethod=self._transport._authmethod)) # remember the user's auth info (this marks the cookie as authenticated) if self._transport._cbtid and self._transport.factory._cookiestore: cs = self._transport.factory._cookiestore cs.setAuth(self._transport._cbtid, self._transport._authid, self._transport._authrole, self._transport._authmethod) # kick all sessions using same cookie (but not _this_ connection) if True: for proto in cs.getProtos( self._transport._cbtid): if proto and proto != self._transport: try: proto.close() except Exception as e: pass else: self.log.info("Authentication failed!") self.log.info(res) dres.callback( types.Deny( reason="wamp.error.authorization_failed", message=res.get("reason", None))) except Exception as e: self.log.info( "internal error during authentication verification: {}" .format(e)) dres.callback( types.Deny(reason="wamp.error.internal_error", message=str(e))) def error(err): self.log.info("Authentication request failed: {}".format( err.value)) dres.callback( types.Deny( reason="wamp.error.authorization_request_failed", message=str(err.value))) d.addCallbacks(done, error) return dres else: self.log.info("don't know how to authenticate") return types.Deny() else: # deny client return types.Deny(message=u"no pending authentication")
def onHello(self, realm, details): try: # check if the realm the session wants to join actually exists # if realm not in self._router_factory: return types.Deny( ApplicationError.NO_SUCH_REALM, message="no realm '{}' exists on this router".format( realm)) authmethods = details.authmethods or ["anonymous"] # perform authentication # if self._transport._authid is not None and ( self._transport._authmethod == u'trusted' or self._transport._authprovider in authmethods): # already authenticated .. e.g. via HTTP Cookie or TLS client-certificate # check if role still exists on realm # allow = self._router_factory[realm].has_role( self._transport._authrole) if allow: return types.Accept( authid=self._transport._authid, authrole=self._transport._authrole, authmethod=self._transport._authmethod, authprovider=self._transport._authprovider) else: return types.Deny( ApplicationError.NO_SUCH_ROLE, message= "session was previously authenticated (via transport), but role '{}' no longer exists on realm '{}'" .format(self._transport._authrole, realm)) else: # if authentication is enabled on the transport .. # if "auth" in self._transport_config: # iterate over authentication methods announced by client .. # for authmethod in authmethods: # .. and if the configuration has an entry for the authmethod # announced, process .. if authmethod in self._transport_config["auth"]: # "WAMP-Challenge-Response" authentication # if authmethod == u"wampcra": cfg = self._transport_config['auth']['wampcra'] if cfg['type'] == 'static': if details.authid in cfg.get('users', {}): user = cfg['users'][details.authid] # the authid the session will be authenticated as is from the user data, or when # the user data doesn't contain an authid, from the HELLO message the client sent # authid = user.get( "authid", details.authid) # construct a pending WAMP-CRA authentication # self._pending_auth = PendingAuthWampCra( details.pending_session, authid, user['role'], u'static', user['secret'].encode('utf8')) # send challenge to client # extra = { u'challenge': self._pending_auth.challenge } # when using salted passwords, provide the client with # the salt and then PBKDF2 parameters used # if 'salt' in user: extra[u'salt'] = user['salt'] extra[u'iterations'] = user.get( 'iterations', 1000) extra[u'keylen'] = user.get( 'keylen', 32) return types.Challenge( u'wampcra', extra) else: return types.Deny( message= "no user with authid '{}' in user database" .format(details.authid)) elif cfg['type'] == 'dynamic': # call the configured dynamic authenticator procedure # via the router's service session # service_session = self._router_factory.get( realm)._realm.session session_details = { # forward transport level details of the WAMP session that # wishes to authenticate 'transport': self._transport._transport_info, # the following WAMP session ID will be assigned to the session # if (and only if) the subsequent authentication succeeds. 'session': self._pending_session_id } d = service_session.call( cfg['authenticator'], realm, details.authid, session_details) def on_authenticate_ok(user): # the authid the session will be authenticated as is from the dynamic # authenticator response, or when the response doesn't contain an authid, # from the HELLO message the client sent # authid = user.get( "authid", details.authid) # construct a pending WAMP-CRA authentication # self._pending_auth = PendingAuthWampCra( details.pending_session, authid, user['role'], u'dynamic', user['secret'].encode('utf8')) # send challenge to client # extra = { u'challenge': self._pending_auth.challenge } # when using salted passwords, provide the client with # the salt and the PBKDF2 parameters used # if 'salt' in user: extra[u'salt'] = user['salt'] extra[u'iterations'] = user.get( 'iterations', 1000) extra[u'keylen'] = user.get( 'keylen', 32) return types.Challenge( u'wampcra', extra) def on_authenticate_error(err): error = None message = "dynamic WAMP-CRA credential getter failed: {}".format( err) if isinstance(err.value, ApplicationError): error = err.value.error if err.value.args and len( err.value.args): message = str( err.value.args[0] ) # exception does not need to contain a string return types.Deny(error, message) d.addCallbacks(on_authenticate_ok, on_authenticate_error) return d else: return types.Deny( message= "illegal WAMP-CRA authentication config (type '{0}' is unknown)" .format(cfg['type'])) # WAMP-Ticket authentication # elif authmethod == u"ticket": cfg = self._transport_config['auth']['ticket'] # use static principal database from configuration # if cfg['type'] == 'static': if details.authid in cfg.get( 'principals', {}): principal = cfg['principals'][ details.authid] # the authid the session will be authenticated as is from the principal data, or when # the principal data doesn't contain an authid, from the HELLO message the client sent # authid = principal.get( "authid", details.authid) self._pending_auth = PendingAuthTicket( realm, authid, principal['role'], u'static', principal['ticket'].encode('utf8')) return types.Challenge(u'ticket') else: return types.Deny( message= "no principal with authid '{}' in principal database" .format(details.authid)) # use configured procedure to dynamically get a ticket for the principal # elif cfg['type'] == 'dynamic': self._pending_auth = PendingAuthTicket( realm, details.authid, None, cfg['authenticator'], None) return types.Challenge(u'ticket') else: return types.Deny( message= "illegal WAMP-Ticket authentication config (type '{0}' is unknown)" .format(cfg['type'])) # "Mozilla Persona" authentication # elif authmethod == u"mozilla_persona": cfg = self._transport_config['auth'][ 'mozilla_persona'] audience = cfg.get('audience', self._transport._origin) provider = cfg.get( 'provider', "https://verifier.login.persona.org/verify" ) # authrole mapping # authrole = cfg.get('role', 'anonymous') # check if role exists on realm anyway # if not self._router_factory[realm].has_role( authrole): return types.Deny( ApplicationError.NO_SUCH_ROLE, message= "authentication failed - realm '{}' has no role '{}'" .format(realm, authrole)) # ok, now challenge the client for doing Mozilla Persona auth. # self._pending_auth = PendingAuthPersona( provider, audience, authrole) return types.Challenge("mozilla-persona") # "Anonymous" authentication # elif authmethod == u"anonymous": cfg = self._transport_config['auth'][ 'anonymous'] # authrole mapping # authrole = cfg.get('role', 'anonymous') # check if role exists on realm anyway # if not self._router_factory[realm].has_role( authrole): return types.Deny( ApplicationError.NO_SUCH_ROLE, message= "authentication failed - realm '{}' has no role '{}'" .format(realm, authrole)) # authid generation if self._transport._cbtid: # if cookie tracking is enabled, set authid to cookie value authid = self._transport._cbtid else: # if no cookie tracking, generate a random value for authid authid = util.newid(24) self._transport._authid = authid self._transport._authrole = authrole self._transport._authmethod = authmethod return types.Accept( authid=authid, authrole=authrole, authmethod=self._transport._authmethod) # "Cookie" authentication # elif authmethod == u"cookie": # the client requested cookie authentication, but there is 1) no cookie set, # or 2) a cookie set, but that cookie wasn't authenticated before using # a different auth method (if it had been, we would never have entered here, since then # auth info would already have been extracted from the transport) # consequently, we skip this auth method and move on to next auth method. pass # Unknown authentication method # else: self.log.info("unknown authmethod '{}'".format( authmethod)) return types.Deny( message="unknown authentication method {}". format(authmethod)) # if authentication is configured, by default, deny. # return types.Deny( message= "authentication using method '{}' denied by configuration" .format(authmethod)) else: # if authentication is _not_ configured, by default, allow anyone. # # authid generation if self._transport._cbtid: # if cookie tracking is enabled, set authid to cookie value authid = self._transport._cbtid else: # if no cookie tracking, generate a random value for authid authid = util.newid(24) return types.Accept(authid=authid, authrole="anonymous", authmethod="anonymous") except Exception as e: traceback.print_exc() return types.Deny(message="internal error: {}".format(e))
def onAuthenticate(self, signature, extra): """ Callback fired when a client responds to an authentication challenge. """ print("onAuthenticate: {} {}".format(signature, extra)) ## if there is a pending auth, and the signature provided by client matches .. if self._pending_auth: if isinstance(self._pending_auth, PendingAuthWampCra): if signature == self._pending_auth.signature: ## accept the client return types.Accept( authid=self._pending_auth.authid, authrole=self._pending_auth.authrole, authmethod=self._pending_auth.authmethod, authprovider=self._pending_auth.authprovider) else: ## deny client return types.Deny(message=u"signature is invalid") elif isinstance(self._pending_auth, PendingAuthPersona): dres = Deferred() ## The client did it's Mozilla Persona authentication thing ## and now wants to verify the authentication and login. assertion = signature audience = str(self._pending_auth.audience ) # eg "http://192.168.1.130:8080/" provider = str( self._pending_auth.provider ) # eg "https://verifier.login.persona.org/verify" ## To verify the authentication, we need to send a HTTP/POST ## to Mozilla Persona. When successful, Persona will send us ## back something like: # { # "audience": "http://192.168.1.130:8080/", # "expires": 1393681951257, # "issuer": "gmail.login.persona.org", # "email": "*****@*****.**", # "status": "okay" # } headers = {'Content-Type': 'application/x-www-form-urlencoded'} body = urllib.urlencode({ 'audience': audience, 'assertion': assertion }) from twisted.web.client import getPage d = getPage(url=provider, method='POST', postdata=body, headers=headers) log.msg("Authentication request sent.") def done(res): res = json.loads(res) try: if res['status'] == 'okay': ## awesome: Mozilla Persona successfully authenticated the user self._transport._authid = res['email'] self._transport._authrole = self._pending_auth.role self._transport._authmethod = 'mozilla_persona' log.msg( "Authenticated user {} with role {}".format( self._transport._authid, self._transport._authrole)) dres.callback( types.Accept( authid=self._transport._authid, authrole=self._transport._authrole, authmethod=self._transport._authmethod)) ## remember the user's auth info (this marks the cookie as authenticated) if self._transport._cbtid and self._transport.factory._cookiestore: cs = self._transport.factory._cookiestore cs.setAuth(self._transport._cbtid, self._transport._authid, self._transport._authrole, self._transport._authmethod) ## kick all sessions using same cookie (but not _this_ connection) if True: for proto in cs.getProtos( self._transport._cbtid): if proto and proto != self._transport: try: proto.close() except Exception as e: pass else: log.msg("Authentication failed!") log.msg(res) dres.callback( types.Deny( reason="wamp.error.authorization_failed", message=res.get("reason", None))) except Exception as e: log.msg( "internal error during authentication verification: {}" .format(e)) dres.callback( types.Deny(reason="wamp.error.internal_error", message=str(e))) def error(err): log.msg("Authentication request failed: {}".format( err.value)) dres.callback( types.Deny( reason="wamp.error.authorization_request_failed", message=str(err.value))) d.addCallbacks(done, error) return dres else: log.msg("don't know how to authenticate") return types.Deny() else: ## deny client return types.Deny(message=u"no pending authentication")
def onHello(self, realm, details): try: ## check if the realm the session wants to join actually exists ## if realm not in self._router_factory: return types.Deny( ApplicationError.NO_SUCH_REALM, message="no realm '{}' exists on this router".format( realm)) ## perform authentication ## if self._transport._authid is not None: ## already authenticated .. e.g. via cookie ## check if role still exists on realm ## allow = self._router_factory[realm].has_role( self._transport._authrole) if allow: return types.Accept(authid=self._transport._authid, authrole=self._transport._authrole, authmethod=self._transport._authmethod, authprovider='transport') else: return types.Deny( ApplicationError.NO_SUCH_ROLE, message= "session was previously authenticated (via transport), but role '{}' no longer exists on realm '{}'" .format(self._transport._authrole, realm)) else: ## if authentication is enabled on the transport .. ## if "auth" in self._transport_config: ## iterate over authentication methods announced by client .. ## for authmethod in details.authmethods or ["anonymous"]: ## .. and if the configuration has an entry for the authmethod ## announced, process .. if authmethod in self._transport_config["auth"]: ## "WAMP-Challenge-Response" authentication ## if authmethod == u"wampcra": cfg = self._transport_config['auth']['wampcra'] if cfg['type'] == 'static': if details.authid in cfg.get('users', {}): user = cfg['users'][details.authid] self._pending_auth = PendingAuthWampCra( details.pending_session, details.authid, user['role'], u'static', user['secret'].encode('utf8')) ## send challenge to client ## extra = { u'challenge': self._pending_auth.challenge } ## when using salted passwords, provide the client with ## the salt and then PBKDF2 parameters used if 'salt' in user: extra[u'salt'] = user['salt'] extra[u'iterations'] = user.get( 'iterations', 1000) extra[u'keylen'] = user.get( 'keylen', 32) return types.Challenge( u'wampcra', extra) else: return types.Deny( message= "no user with authid '{}' in user database" .format(details.authid)) elif cfg['type'] == 'dynamic': ## Get the Crossbar.io service session on the router/realm ## to issue the WAMP call to the custom authorizer ## router = self._router_factory.get(realm) service_session = router._realm.session d = service_session.call( cfg['authenticator'], realm, details.authid) def on_authenticate_ok(user): ## construct a pending WAMP-CRA authentication ## self._pending_auth = PendingAuthWampCra( details.pending_session, details.authid, user['role'], u'dynamic', user['secret'].encode('utf8')) ## send challenge to client ## extra = { u'challenge': self._pending_auth.challenge } ## when using salted passwords, provide the client with ## the salt and the PBKDF2 parameters used ## if 'salt' in user: extra[u'salt'] = user['salt'] extra[u'iterations'] = user.get( 'iterations', 1000) extra[u'keylen'] = user.get( 'keylen', 32) return types.Challenge( u'wampcra', extra) def on_authenticate_error(err): error = None message = "dynamic WAMP-CRA credential getter failed: {}".format( err) if isinstance(err.value, ApplicationError): error = err.value.error if err.value.args and len( err.value.args): message = err.value.args[0] return types.Deny(error, message) d.addCallbacks(on_authenticate_ok, on_authenticate_error) return d else: return types.Deny( message= "illegal WAMP-CRA config (type '{0}' is unknown)" .format(cfg['type'])) ## "Mozilla Persona" authentication ## elif authmethod == u"mozilla_persona": cfg = self._transport_config['auth'][ 'mozilla_persona'] audience = cfg.get('audience', self._transport._origin) provider = cfg.get( 'provider', "https://verifier.login.persona.org/verify" ) ## authrole mapping ## authrole = cfg.get('role', 'anonymous') ## check if role exists on realm anyway ## if not self._router_factory[realm].has_role( authrole): return types.Deny( ApplicationError.NO_SUCH_ROLE, message= "authentication failed - realm '{}' has no role '{}'" .format(realm, authrole)) ## ok, now challenge the client for doing Mozilla Persona auth. ## self._pending_auth = PendingAuthPersona( provider, audience, authrole) return types.Challenge("mozilla-persona") ## "Anonymous" authentication ## elif authmethod == u"anonymous": cfg = self._transport_config['auth'][ 'anonymous'] ## authrole mapping ## authrole = cfg.get('role', 'anonymous') ## check if role exists on realm anyway ## if not self._router_factory[realm].has_role( authrole): return types.Deny( ApplicationError.NO_SUCH_ROLE, message= "authentication failed - realm '{}' has no role '{}'" .format(realm, authrole)) ## authid generation ## if self._transport._cbtid: ## if cookie tracking is enabled, set authid to cookie value ## authid = self._transport._cbtid else: ## if no cookie tracking, generate a random value for authid ## authid = util.newid(24) self._transport._authid = authid self._transport._authrole = authrole self._transport._authmethod = authmethod return types.Accept( authid=authid, authrole=authrole, authmethod=self._transport._authmethod) ## "Cookie" authentication ## elif authmethod == u"cookie": pass # if self._transport._cbtid: # cookie = self._transport.factory._cookies[self._transport._cbtid] # authid = cookie['authid'] # authrole = cookie['authrole'] # authmethod = "cookie.{}".format(cookie['authmethod']) # return types.Accept(authid = authid, authrole = authrole, authmethod = authmethod) # else: # return types.Deny() else: log.msg("unknown authmethod '{}'".format( authmethod)) return types.Deny( message="unknown authentication method {}". format(authmethod)) ## if authentication is configured, by default, deny. ## return types.Deny( message= "authentication using method '{}' denied by configuration" .format(authmethod)) else: ## if authentication is _not_ configured, by default, allow anyone. ## ## authid generation ## if self._transport._cbtid: ## if cookie tracking is enabled, set authid to cookie value ## authid = self._transport._cbtid else: ## if no cookie tracking, generate a random value for authid ## authid = util.newid(24) return types.Accept(authid=authid, authrole="anonymous", authmethod="anonymous") except Exception as e: traceback.print_exc() return types.Deny(message="internal error: {}".format(e))
def onHello(self, realm, details): return types.Accept()
def onAuthenticate(self, signature, extra): return types.Accept()
def on_authenticate_ok(role): return types.Accept(authid = self._pending_auth.authid, authrole = role, authmethod = self._pending_auth.authmethod, authprovider = self._pending_auth.authprovider)
def onHello(self, realm, details): if self._transport._authid is not None: ## already authenticated .. e.g. via cookie ## return types.Accept(authid=self._transport._authid, authrole=self._transport._authrole, authmethod=self._transport._authmethod) else: ## if authentication is enabled on the transport .. ## if "auth" in self._transport_config: ## iterate over authentication methods announced by client .. ## for authmethod in details.authmethods or ["anonymous"]: ## .. and if the configuration has an entry for the authmethod ## announced, process .. if authmethod in self._transport_config["auth"]: ## Mozilla Persona ## if authmethod == "mozilla_persona": cfg = self._transport_config['auth'][ 'mozilla_persona'] audience = cfg.get('audience', self._transport._origin) provider = cfg.get( 'provider', "https://verifier.login.persona.org/verify") ## authrole mapping ## authrole = None try: if 'role' in cfg: if cfg['role']['type'] == 'static': authrole = cfg['role']['value'] except Exception as e: log.msg( "error processing 'role' part of 'auth' config: {}" .format(e)) self._pending_auth = PendingAuthPersona( provider, audience, authrole) return types.Challenge("mozilla-persona") ## Anonymous ## elif authmethod == "anonymous": cfg = self._transport_config['auth']['anonymous'] ## authrole mapping ## authrole = "anonymous" try: if 'role' in cfg: if cfg['role']['type'] == 'static': authrole = cfg['role']['value'] except Exception as e: log.msg( "error processing 'role' part of 'auth' config: {}" .format(e)) ## authid generation ## if self._transport._cbtid: ## set authid to cookie value authid = self._transport._cbtid else: authid = util.newid(24) self._transport._authid = authid self._transport._authrole = authrole self._transport._authmethod = "anonymous" return types.Accept( authid=authid, authrole=authrole, authmethod=self._transport._authmethod) elif authmethod == "cookie": pass # if self._transport._cbtid: # cookie = self._transport.factory._cookies[self._transport._cbtid] # authid = cookie['authid'] # authrole = cookie['authrole'] # authmethod = "cookie.{}".format(cookie['authmethod']) # return types.Accept(authid = authid, authrole = authrole, authmethod = authmethod) # else: # return types.Deny() else: log.msg( "unknown authmethod '{}'".format(authmethod)) ## if authentication is configured, by default, deny. ## return types.Deny() else: ## FIXME: if not "auth" key present, allow anyone return types.Accept(authid="anonymous", authrole="anonymous", authmethod="anonymous")
def verify(self, signature): """ The WAMP client has answered with a WAMP AUTHENTICATE message. Verify the message and return `types.Accept` or `types.Deny`. """ # WAMP-Ticket "static" # if self.authprovider == 'static': # when doing WAMP-Ticket from static configuration, the ticket we # expect was store on the pending authentication object and we just compare .. if signature == self.ticket: # ticket was valid: accept the client return types.Accept(realm=self.realm, authid=self.authid, authrole=self.authrole, authmethod=self.authmethod, authprovider=self.authprovider) else: # ticket was invalid: deny client return types.Deny(message=u"ticket in static WAMP-Ticket authentication is invalid") # WAMP-Ticket "dynamic" # else: details = { 'transport': self.session._transport._transport_info, 'session': self.session._pending_session_id, 'ticket': signature } d = self.authenticator_session.call(self.authenticator, self.realm, self.authid, details) def on_authenticate_ok(principal): if isinstance(principal, dict): # dynamic ticket authenticator returned a dictionary (new) realm = principal.get("realm", self.realm) authid = principal.get("authid", self.authid) authrole = principal["role"] else: # backwards compatibility: dynamic ticket authenticator # was expected to return a role directly realm = self.realm authid = self.authid authrole = principal return types.Accept(realm=realm, authid=authid, authrole=authrole, authmethod=self.authmethod, authprovider=self.authprovider) def on_authenticate_error(err): error = None message = "WAMP-Ticket dynamic authenticator failed: {}".format(err) if isinstance(err.value, ApplicationError): error = err.value.error if err.value.args and len(err.value.args): message = err.value.args[0] return types.Deny(error, message) d.addCallbacks(on_authenticate_ok, on_authenticate_error) return d