def token(request): # Ensure we've got a JWT jwt = get_jwt(request) if not jwt: return redirect("dbmi_login:login") # Set the token context = {"jwt": jwt} return render(request, template_name="dbmi_client/login/jwt.html", context=context)
def get_jwt_user(request): # Check for a valid token token = authn.get_jwt(request) if not token or not authn.validate_rs256_jwt(token): return AnonymousUser() # Get their username username = authn.get_jwt_username(request, verify=False) # Use the usual routine to get the currently cached user user = django_auth.get_user(request) if user.is_authenticated: logger.debug("Found existing User session: {}".format(username)) # A cached user is present. We need to double-check JWT user to ensure # they are the same as the cached user. username = authn.get_jwt_username(request, verify=False) email = authn.get_jwt_email(request, verify=False) if username and email: if not user.username.lower() == username.lower( ) or not user.email.lower() == email.lower(): logger.debug( "User session does not match JWT, logging out") # TODO: Figure out if its necessary to person any session invalidation here return AnonymousUser() else: logger.debug( "No existing User, attempting to login: {}".format(username)) # No user is logged in but we have a JWT token. Attempt to authenticate # the current JWT and if it succeeds, login and cache the user. user = django_auth.authenticate(request, token=token) if user and user.is_authenticated: logger.debug("User has authenticated: {}".format(username)) # Store this user in session django_auth.login(request, user) else: logger.debug( "User could not be authenticated: {}".format(username)) # Whatever token this user has, it's not valid OR their account would/could not # be created, deny permission. This will likely be the case for instances where # automatic user creation is disabled and a user with a valid JWT is not being # granted an account. raise PermissionDenied return user
def get_jwt_user(request): # Check for a valid token token = authn.get_jwt(request) if not token or not authn.validate_rs256_jwt(token): return AnonymousUser() # Get their username username = authn.get_jwt_username(request, verify=False) # Attempt to authenticate the current JWT. user = django_auth.authenticate(request, token=token) if not user or not user.is_authenticated: logger.debug( "User could not be authenticated: {}".format(username)) # Whatever token this user has, it's not valid OR their account would/could not # be created, deny permission. This will likely be the case for instances where # automatic user creation is disabled and a user with a valid JWT is not being # granted an account. raise PermissionDenied return user
def get_jwt_user(request): # Use super's implementation user = DBMIAuthenticationMiddleware.get_jwt_user(request) if user: # Check if they've been granted admin level privileges if user.is_staff or user.is_superuser: # Get details token = authn.get_jwt(request) username = authn.get_jwt_username(request, verify=False) email = authn.get_jwt_email(request, verify=False) logger.debug( f'User "{username}":"{email}" is currently admin; rerunning sync...' ) # Run their sync again to make absolutely sure they're still an admin user = django_auth.authenticate(request, token=token) if user and user.is_authenticated: logger.debug( "User has re-authenticated: {}".format(username)) # Check updated status if user.is_superuser or user.is_staff: logger.debug( f'User "{username}":"{email}" is still admin') else: logger.debug( "User could not be authenticated: {}".format(username)) # Whatever token this user has, it's not valid OR their account would/could not # be created, deny permission. This will likely be the case for instances where # automatic user creation is disabled and a user with a valid JWT is not being # granted an account. raise PermissionDenied return user
def _headers(request=None): """ Returns the headers to use for Fileservice requests. If a Fileservice token is specified in settings, this will use that token to sign calls, otherwise, the current user's JWT will be used. :param request: The request :return: dict """ if dbmi_settings.FILESERVICE_TOKEN: # Use the service token from environment return {"Authorization": "Token {}".format(dbmi_settings.FILESERVICE_TOKEN), "Content-Type": "application/json"} elif request: # Get the JWT token = authn.get_jwt(request) # Use the service token from environment return {"Authorization": "JWT {}".format(token), "Content-Type": "application/json"} else: raise ValueError("Cannot properly authenticate service call")
def get_permissions(request, email, item=None, children=False): """ Consults the DBMIAuthz server for authorization checks. Uses the JWT to authenticate the call and checks the returned permissions for the one specified. :param request: The current request or JWT to authenticate the call :type HttpRequest: str :param email: The email in the JWT :type email: str :param item: The item string to check for the permission :type item: str :param children: Whether children of the passed item should be returned :type children: bool :return: A list of permissions :rtype: list """ url = None content = None try: # Build the request url = furl(dbmi_settings.AUTHZ_URL) url.path.segments.append("user_permission") url.path.segments.append("") url.query.params.add("email", email) url.query.params.add("client", dbmi_settings.CLIENT) # Include children if children: url.query.params.add("children", "true") # Check for specific item if item: url.query.params.add("item", item) # Get the JWT token depending on request type if type(request) is str: token = request else: token = authn.get_jwt(request) # Ensure we've got a token if not token: return False # Build headers for the SciAuthZ call headers = { "Authorization": "{}{}".format(dbmi_settings.JWT_HTTP_PREFIX, token), "Content-Type": "application/json", } # Run it response = requests.get(url.url, headers=headers) content = response.content response.raise_for_status() return response.json().get("results", []) except (requests.HTTPError, TypeError, KeyError): logger.error( "SciAuthZ permission lookup failed", exc_info=True, extra={ "email": email, "url": url, "content": content, "item": item }, ) return []
def has_a_permission(request, email, item, permissions, check_parents=False): """ Consults the DBMIAuthz server for authorization checks. Uses the JWT to authenticate the call and checks the returned permissions for the one specified. :param request: The current request containing the JWT to be checked or the JWT itself :param email: The email in the JWT :param item: The item string to check for the permission :param permissions: A list of permissions :param check_parents: For every item, also attempt to match parents for the given permission :return: bool """ url = None content = None try: # Build the request url = furl(dbmi_settings.AUTHZ_URL) url.path.segments.append("user_permission") url.path.segments.append("") url.query.params.add("email", email) url.query.params.add("client", dbmi_settings.CLIENT) # If we are searching parents, we need to fetch all permissions for this user if not check_parents: url.query.params.add("item", item) # Get the JWT token depending on request type if type(request) is str: token = request else: token = authn.get_jwt(request) # Ensure we've got a token if not token: return False # Build headers for the SciAuthZ call headers = { "Authorization": "{}{}".format(dbmi_settings.JWT_HTTP_PREFIX, token), "Content-Type": "application/json", } # Run it response = requests.get(url.url, headers=headers) content = response.content response.raise_for_status() # If checking parents... if check_parents and len(item.split(".")) > 1: # ... build list of all parent paths components = item.lower().split(".") items = [ ".".join(components[:i + 1]) for i in range(len(components)) ] else: # Set the single item list to search items = [item.lower()] # Parse permissions for permission_result in response.json().get("results"): # Get the items item = permission_result["item"].lower() permission = permission_result["permission"].lower() # Check it if item in items and permission in map(str.lower, permissions): logger.debug("DBMIAuthZ: {} has {} on {}".format( email, permission, item)) return True except (requests.HTTPError, TypeError, KeyError): logger.error( "SciAuthZ permission lookup failed", exc_info=True, extra={ "request": request, "email": email, "permissions": permissions, "url": url, "content": content }, ) return False