def refresh_token_grant(old_refresh_token: UUID): """Implements logic for refresh token grant.""" # check token exists in database and get expire time and user id collection = RefreshTokens() old_token_document = collection.find_one( {"token": old_refresh_token}, {"expire_time": 1, "user_id": 1} ) if old_token_document is None: raise InvalidGrant("Refresh token is invalid.") # check token is not expired expire_time = old_token_document["expire_time"] if expire_time < datetime.now(): raise InvalidGrant("Refresh token is expired.") # check user exists user_id = old_token_document["user_id"] user = Users().find_one({"_id": user_id}, {"password_hash": 0}) if user is None: raise InvalidGrant("Refresh token is invalid.") # generate token access_token = LoadedAccessToken( user["_id"], user["username"], user.get("scope", {}) ).encode() refresh_token = OAuth2.generate_refresh_token(user["_id"]) # delete old refresh token from database collection.delete_one({"token": old_refresh_token}) collection.delete_many({"expire_time": {"$lte": datetime.now()}}) return OAuth2.success_response(access_token, refresh_token)
def get(self, username: str, token: AccessToken.Payload): # if user in url is not user in token, check user permission if username != token.username: if not token.get_permission("users", "ssh_keys"): raise errors.NotEnoughPrivilege() user = Users().find_one({"username": username}, {"ssh_keys": 1}) if user is None: raise errors.NotFound() ssh_keys = user.get("ssh_keys", []) return jsonify(ssh_keys)
def get(self, token: AccessToken.Payload, username: str): # if user in url is not user in token, check user permission if username != token.username: if not token.get_permission("users", "read"): raise errors.NotEnoughPrivilege() # find user based on _id or username user = Users().find_one( {"username": username}, {"_id": 0, "username": 1, "email": 1, "scope": 1, "ssh_keys": 1}, ) if user is None: raise errors.NotFound() user["role"] = get_role_for(user.get("scope")) return jsonify(user)
def get(self, username: str, fingerprint: str): # list of permission to test the matching user against requested_permissions = request.args.getlist("with_permission") or [] query = {} # request using `-` as username searchs on all users if username != "-": query.update({"username": username}) query.update({"ssh_keys.fingerprint": fingerprint}) # database user = Users().find_one( query, { "username": 1, "scope": 1, "ssh_keys": 1, }, ) # no user means no matching SSH key for fingerprint if not user: raise errors.NotFound() key = [ key for key in user["ssh_keys"] if key["fingerprint"] == fingerprint ][-1] for permission in requested_permissions: namespace, perm_name = permission.split(".", 1) if not user.get("scope", {}).get(namespace, {}).get(perm_name): raise errors.NotEnoughPrivilege(permission) payload = { "username": user["username"], "key": key["key"], "type": key["type"], "name": key["name"], } return jsonify(payload)
def password_grant(username: str, password: str): """Implements logic for password grant.""" # check user exists user = Users().find_one({"username": username}) if user is None: raise InvalidGrant("Username or password is invalid.") # check password is valid password_hash = user.pop("password_hash") is_valid = check_password_hash(password_hash, password) if not is_valid: raise InvalidGrant("Username or password is invalid.") # generate token access_token = LoadedAccessToken( user["_id"], user["username"], user.get("scope", {}) ).encode() refresh_token = OAuth2.generate_refresh_token(user["_id"]) return OAuth2.success_response(access_token, refresh_token)
def post(self, username: str, token: AccessToken.Payload): # if user in url is not user in token, not allowed to add ssh keys if username != token.username: if not token.get_permission("users", "ssh_keys"): raise errors.NotEnoughPrivilege() try: request_json = KeySchema().load(request.get_json()) except ValidationError as e: raise errors.InvalidRequestJSON(e.messages) # parse public key string key = request_json["key"] key_parts = key.split(" ") if len(key_parts) >= 2: key = key_parts[1] # compute fingerprint try: rsa_key = paramiko.RSAKey(data=base64.b64decode(key)) fingerprint = binascii.hexlify(rsa_key.get_fingerprint()).decode() except (binascii.Error, paramiko.SSHException): raise errors.BadRequest("Invalid RSA key") # get existing ssh key fingerprints query = {"username": username} user = Users().find_one(query, {"ssh_keys.fingerprint": 1}) if user is None: raise errors.NotFound() # find out if new ssh already exist fingerprints = set( [ssh_key["fingerprint"] for ssh_key in user.get("ssh_keys", [])] ) if fingerprint in fingerprints: raise errors.BadRequest("SSH key already exists") # add new ssh key to database ssh_key = { "name": request_json["name"], # ssh-keygen -l -f xxx.pub -E md5 - just data, without dots "fingerprint": fingerprint, "key": key, "type": "RSA", "added": datetime.now(), "last_used": None, } # get PKCS8 - ssh-keygen -e -f xxx.priv -m PKCS8 with tempfile.NamedTemporaryFile(mode="w", suffix=".pub", delete=False) as fp: fp.write("ssh-rsa {} {}\n".format(ssh_key["key"], ssh_key["name"])) keygen = subprocess.run( ["/usr/bin/ssh-keygen", "-e", "-f", fp.name, "-m", "PKCS8"], capture_output=True, text=True, ) if keygen.returncode != 0: raise errors.BadRequest(keygen.stderr) ssh_key.update({"pkcs8_key": keygen.stdout}) os.unlink(fp.name) Users().update_one(query, {"$push": {"ssh_keys": ssh_key}}) return Response(status=HTTPStatus.CREATED)