def check_nonce(): """ This function is an agaveflask authentication callback used to process the existence of a query parameter, x-nonce, an alternative authentication mechanism to JWT. When an x-nonce query parameter is provided, the request context is updated with the identity of the user owning the actor to which the nonce belongs. Note that the roles of said user will not be calculated so, in particular, any privileged action cannot be taken via a nonce. """ logger.debug("top of check_nonce") try: nonce_id = request.args['x-nonce'] except KeyError: raise PermissionsException("No JWT or nonce provided.") logger.debug("checking nonce with id: {}".format(nonce_id)) # the nonce encodes the tenant in its id: g.tenant = Nonce.get_tenant_from_nonce_id(nonce_id) g.api_server = get_api_server(g.tenant) logger.debug("tenant associated with nonce: {}".format(g.tenant)) # get the actor_id base on the request path actor_id = get_db_id() logger.debug("db_id: {}".format(actor_id)) level = required_level(request) Nonce.check_and_redeem_nonce(actor_id, nonce_id, level) # if we were able to redeem the nonce, update auth context with the actor owner data: logger.debug("nonce valid and redeemed.") nonce = Nonce.get_nonce(actor_id, nonce_id) g.user = nonce.owner # update roles data with that stored on the nonce: g.roles = nonce.roles # now, manually call our authorization function: authorization()
def post(self, actor_id): """Create a new nonce for an actor.""" logger.debug("top of POST /actors/{}/nonces".format(actor_id)) dbid = Actor.get_dbid(g.tenant, actor_id) try: Actor.from_db(actors_store[dbid]) except KeyError: logger.debug("did not find actor: {}.".format(actor_id)) raise ResourceError( "No actor found with id: {}.".format(actor_id), 404) args = self.validate_post() logger.debug("nonce post args validated: {}.".format(actor_id)) # supply "provided" fields: args['tenant'] = g.tenant args['api_server'] = g.api_server args['db_id'] = dbid args['owner'] = g.user args['roles'] = g.roles # create and store the nonce: nonce = Nonce(**args) Nonce.add_nonce(dbid, nonce) logger.info("nonce added for actor: {}.".format(actor_id)) return ok(result=nonce.display(), msg="Actor nonce created successfully.")
def lookup_nonce(self, oauth_consumer, oauth_token, nonce): if oauth_token is None: return None logger.warning("!!! In GAEOAuthDataStore.lookup_nonce key_:%s, consumer_key: %s, token_key:%s"%(nonce,oauth_consumer.key_,oauth_token.key_)) nonces = Nonce.all()\ .filter('consumer_key =',oauth_consumer.key_)\ .filter('token_key =',oauth_token.key_)\ .filter('key_ =',nonce).fetch(1000) if len(nonces) == 1: nonce = nonces[0] return nonce.key_ elif len(nonces) == 0: #create a nonce nonce_obj = Nonce(consumer_key=oauth_consumer.key_, token_key=oauth_token.key_, key_=nonce) nonce_obj.put() return None else: raise Exception('More then one nonce matches consumer_key "%s", \ token_key "%s", key_ "%S"'%(oauth_consumer.key,oauth_token.key, nonce))
def get(self, request): """ This function initializes the authentication process It builds a challenge which is sent to the client """ # Creates a new nonce associated to this session nonce = Nonce() nonce.save() # Gets the callback uri callback_uri = self.get_callback_uri(request) # Builds the challenge (bitid uri) bitid_uri = bitid.build_uri(callback_uri, nonce.nid) # Gets the qrcode uri qrcode = bitid.qrcode(bitid_uri) context = { "callback_uri": callback_uri, "bitid_uri": bitid_uri, "qrcode": qrcode } return render(request, self.template_name, context)
def useNonce(self, server_url, timestamp, salt): if abs(timestamp - time.time()) > oid_nonce.SKEW: return False try: nonce = Nonce( server_url=server_url, timestamp=timestamp, salt=salt) nonce.save() except: raise else: return 1
def delete(self, actor_id, nonce_id): """Delete a nonce.""" logger.debug("top of DELETE /actors/{}/nonces/{}".format(actor_id, nonce_id)) dbid = Actor.get_dbid(g.tenant, actor_id) try: Actor.from_db(actors_store[dbid]) except KeyError: logger.debug("did not find actor: {}.".format(actor_id)) raise ResourceError( "No actor found with id: {}.".format(actor_id), 404) Nonce.delete_nonce(dbid, nonce_id) return ok(result=None, msg="Actor nonce deleted successfully.")
def validate_timestamp_and_nonce(self, client_key, timestamp, nonce, request_token=None, access_token=None): token = True req_token = True client = Client.query(Client.client_key == client_key).get() if client: nonce = Nonce.query(Nonce.nonce == nonce, Nonce.timestamp == timestamp, Nonce.client == client.key).get() if nonce: if request_token: req_token = nonce.request_token.get() if req_token and req_token.token == request_token: return False if access_token: token = nonce.access_token.get() if token and token.token == access_token: return False return True else: return False
def save_nonce(client_key, timestamp, nonce, request_token, access_token): n = Nonce(client_key=client_key, timestamp=timestamp, nonce=nonce, request_token=request_token, access_token=access_token) nonces.append(n) return n
def save_timestamp_and_nonce(self, client_key, timestamp, nonce, request_token=None, access_token=None): nonce = Nonce(nonce, timestamp) nonce.client = Client.query.filter_by(client_key=client_key).one() if request_token: nonce.token = RequestToken.query.filter_by( token=request_token).one() if access_token: nonce.token = AccessToken.query.filter_by(token=access_token).one() db_session.add(nonce) db_session.commit()
def get(self, actor_id): logger.debug("top of GET /actors/{}/nonces".format(actor_id)) dbid = Actor.get_dbid(g.tenant, actor_id) try: Actor.from_db(actors_store[dbid]) except KeyError: logger.debug("did not find actor: {}.".format(actor_id)) raise ResourceError( "No actor found with id: {}.".format(actor_id), 404) nonces = Nonce.get_nonces(actor_id=dbid) return ok(result=[n.display() for n in nonces], msg="Actor nonces retrieved successfully.")
def get(self, actor_id, nonce_id): """Lookup details about a nonce.""" logger.debug("top of GET /actors/{}/nonces/{}".format(actor_id, nonce_id)) dbid = Actor.get_dbid(g.tenant, actor_id) try: Actor.from_db(actors_store[dbid]) except KeyError: logger.debug("did not find actor: {}.".format(actor_id)) raise ResourceError( "No actor found with id: {}.".format(actor_id), 404) nonce = Nonce.get_nonce(actor_id=dbid, nonce_id=nonce_id) return ok(result=nonce.display(), msg="Actor nonce retrieved successfully.")
def validate_post(self): parser = Nonce.request_parser() try: args = parser.parse_args() except BadRequest as e: msg = 'Unable to process the JSON description.' if hasattr(e, 'data'): msg = e.data.get('message') raise DAOError("Invalid nonce description: {}".format(msg)) # additional checks if 'level' in args: if not args['level'] in PERMISSION_LEVELS: raise DAOError("Invalid nonce description. " "The level attribute must be one of: {}".format(PERMISSION_LEVELS)) if Config.get('web', 'case') == 'snake': if 'max_uses' in args: self.validate_max_uses(args['max_uses']) else: if 'maxUses' in args: self.validate_max_uses(args['maxUses']) return args
def setUp(self): self.user = User(username='******', password='******') self.client = Client(user=self.user, redirect_uris=[REDIRECT_URI], realms=['read'], client_key=CONSUMER_KEY, client_secret=CONSUMER_SECRET) self.request_token = RequestToken(client=self.client, token=REQUEST_TOKEN, secret=REQUEST_TOKEN_SECRET, redirect_uri=REDIRECT_URI, realms=['read'], user=self.user) self.access_token = AccessToken(client=self.client, user=self.user, realms=[REDIRECT_URI], token=ACCESS_TOKEN, secret=ACCESS_TOKEN_SECRET) self.nonce = Nonce(client_key=self.client.client_key, timestamp=TIMESTAMP, nonce=NONCE, request_token=REQUEST_TOKEN, access_token=ACCESS_TOKEN)
def save_timestamp_and_nonce(self, client_key, timestamp, nonce, request_token=None, access_token=None): client = Client.find_one({'client_key': client_key}) if client: nonce = Nonce(nonce, timestamp) nonce.client_id = client['_id'] if request_token: req_token = RequestToken.find_one({'token': request_token}) nonce.request_token_id = req_token['_id'] if access_token: token = AccessToken.find_one({'token': access_token}) nonce.access_token_id = token['_id'] nonce.insert()
def validate_timestamp_and_nonce(self, client_key, timestamp, nonce, request_token=None, access_token=None): token = True req_token = True client = Client.find_one({'client_key': client_key}) if client: nonce = Nonce.find_one({ 'nonce': nonce, 'timestamp': timestamp, 'client_id': client['_id'] }) if nonce: if request_token: req_token = RequestToken.find_one({ '_id': nonce['request_token_id'], 'token': request_token }) if access_token: token = RequestToken.find_one({ '_id': nonce['request_token_id'], 'token': access_token }) return token and req_token and nonce != None
def useNonce(self, server_url, timestamp, salt): if abs(timestamp - time.time()) > openid_store.nonce.SKEW: return False query = [ Q(server_url__exact=server_url), Q(timestamp__exact=timestamp), Q(salt__exact=salt), ] try: ononce = Nonce.objects.get(reduce(operator.and_, query)) except Nonce.DoesNotExist: ononce = Nonce(server_url=server_url, timestamp=timestamp, salt=salt) ononce.save() return True ononce.delete() return False
def save_timestamp_and_nonce(self, client_key, timestamp, nonce, request_token=None, access_token=None): client = Client.query(Client.client_key == client_key).get() if client: nonce = Nonce(nonce=nonce, timestamp=timestamp, client=client.key) if request_token: req_token = RequestToken.query( RequestToken.token == request_token).get() nonce.request_token = req_token.key if access_token: token = AccessToken.query( AccessToken.token == access_token).get() nonce.access_token = token.key nonce.put()
def post(self, code=None): response = RESPONSE.copy() if not code: desc = "There is/are missing parameters in the request." response["response"] = "MissingParameters" response["description"] = desc response["code"] = 463 if "X-Signature" in self.request.headers: c_sig = self.request.headers['X-Signature'] s_data = "&".join([ "POST", urllib.quote(self.request.uri), urllib.quote(self.request.body) ]) s_sig = generate_signature(LOGIN_KEY, s_data) logging.info("v: " + s_sig) if c_sig == s_sig: try: body = json.loads(self.request.body) except: desc = "The request body is not in a valid JSON format." response["response"] = "InvalidJSONFormat" response["description"] = desc response["code"] = 406 else: if "nonce" in body and "timestamp" in body: new = False nn = Nonce.get_by_id(body["nonce"]) if nn: expiry = datetime.datetime.now() expiry = int(time.mktime(expiry.timetuple())) expiry -= int(nn.timestamp) expiry /= 60 expiry /= 60 if expiry <= 10: new = True else: desc = "This request seems to be expired already" response["response"] = "RequestExpired" response["description"] = desc response["code"] = 464 else: n = Nonce(id=body["nonce"]) n.nonce = body["nonce"] n.timestamp = int(body["timestamp"]) n.put() new = True if new: logincode = LoginCode.get_by_id(str(code)) if logincode: s = logincode.session.get() if s.expires >= datetime.datetime.now(): user = s.owner.get() if user: t_id = generate_uuid() + generate_uuid( ) token = Token(id=t_id) token.token = t_id token.session = s.key token.token_type = "api" token.put() response = user.to_object(token=t_id) response["response"] = "Successful" response["expires"] = time.mktime( s.expires.timetuple()) response["code"] = 200 else: s.status = False s.put() response[ "response"] = "UserUnavailable" response[ "description"] = "This user seems to be unavailable" response["code"] = 404 else: response["response"] = "SessionExpired" response[ "description"] = "This session seems to be expired already" response["code"] = 465 else: response["response"] = "LoginCodeDoesNotExist" response[ "description"] = "This login code does not exist." response["code"] = 404 else: response["response"] = "MissingParameters" response[ "description"] = "There is/are missing parameters in the request." response["code"] = 463 else: response["response"] = "InvalidSignature" response[ "description"] = "The request signature is invalid or has been tampered." response["code"] = 460 else: response["response"] = "MissingParameters" response[ "description"] = "There is/are missing parameters in the request." response["code"] = 463 wrap_response(self, response)
def check_nonce(): """ This function is an agaveflask authentication callback used to process the existence of a query parameter, x-nonce, an alternative authentication mechanism to JWT. When an x-nonce query parameter is provided, the request context is updated with the identity of the user owning the actor to which the nonce belongs. Note that the roles of said user will not be calculated so, in particular, any privileged action cannot be taken via a nonce. """ logger.debug("top of check_nonce") # first check whether the request is even valid - if hasattr(request, 'url_rule'): logger.debug("request.url_rule: {}".format(request.url_rule)) if hasattr(request.url_rule, 'rule'): logger.debug("url_rule.rule: {}".format(request.url_rule.rule)) else: logger.info("url_rule has no rule.") raise ResourceError( "Invalid request: the API endpoint does not exist or the provided HTTP method is not allowed.", 405) else: logger.info("Request has no url_rule") raise ResourceError( "Invalid request: the API endpoint does not exist or the provided HTTP method is not allowed.", 405) try: nonce_id = request.args['x-nonce'] except KeyError: raise PermissionsException("No JWT or nonce provided.") logger.debug("checking nonce with id: {}".format(nonce_id)) # the nonce encodes the tenant in its id: g.tenant = Nonce.get_tenant_from_nonce_id(nonce_id) g.api_server = get_api_server(g.tenant) logger.debug( "tenant associated with nonce: {}; api_server assoicated with nonce: {}" .format(g.tenant, g.api_server)) # get the actor_id base on the request path actor_id, actor_identifier = get_db_id() logger.debug("db_id: {}; actor_identifier: {}".format( actor_id, actor_identifier)) level = required_level(request) # if the actor_identifier is an alias, then the nonce must be attached to that, so we must pass that in the # nonce check: if is_hashid(actor_identifier): Nonce.check_and_redeem_nonce(actor_id=actor_id, alias=None, nonce_id=nonce_id, level=level) else: alias_id = Alias.generate_alias_id(tenant=g.tenant, alias=actor_identifier) Nonce.check_and_redeem_nonce(actor_id=None, alias=alias_id, nonce_id=nonce_id, level=level) # if we were able to redeem the nonce, update auth context with the actor owner data: logger.debug("nonce valid and redeemed.") if is_hashid(actor_identifier): nonce = Nonce.get_nonce(actor_id=actor_id, alias=None, nonce_id=nonce_id) else: nonce = Nonce.get_nonce(actor_id=None, alias=alias_id, nonce_id=nonce_id) g.user = nonce.owner # update roles data with that stored on the nonce: g.roles = nonce.roles # now, manually call our authorization function: authorization()