Add User Info to created tasks (#303)

This PR makes user information from JWT tokens available as part of a Task.

Included changes:
* Renamed `verify_token` to `call_if_agent`, since this function is specific to agent token verification
* Renames `is_authorized` to `is_agent`, since this function checks if the token is an agent
* Adds support for unmanaged nodes in `is_agent` (see #133 for information) 
* Saves the user information from the JWT token on task create as part of `TaskConfig`

Note, `TaskConfig` is what is provided to notification templates.  This enables Github issues and ADO work items to tie back to the user that created the task.

Note, while `upn` _usually_ means email for AAD user tokens.  If we were going to make use of the email address, we should perform a graph lookup based on the `oid`, but we're not.
This commit is contained in:
bmc-msft
2020-11-13 06:50:52 -05:00
committed by GitHub
parent 31f099d3d4
commit beea318968
13 changed files with 254 additions and 71 deletions

View File

@ -0,0 +1,42 @@
#!/usr/bin/env python
#
# Copyright (c) Microsoft Corporation.
# Licensed under the MIT License.
from uuid import UUID
import azure.functions as func
import jwt
from onefuzztypes.enums import ErrorCode
from onefuzztypes.models import Error, Result, UserInfo
def parse_jwt_token(request: func.HttpRequest) -> Result[UserInfo]:
""" Obtains the Access Token from the Authorization Header """
auth: str = request.headers.get("Authorization", None)
if not auth:
return Error(
code=ErrorCode.INVALID_REQUEST, errors=["Authorization header is expected"]
)
parts = auth.split()
if len(parts) != 2:
return Error(
code=ErrorCode.INVALID_REQUEST, errors=["Invalid authorization header"]
)
if parts[0].lower() != "bearer":
return Error(
code=ErrorCode.INVALID_REQUEST,
errors=["Authorization header must start with Bearer"],
)
# This token has already been verified by the azure authentication layer
token = jwt.decode(parts[1], verify=False)
application_id = UUID(token["appid"])
object_id = UUID(token["oid"]) if "oid" in token else None
upn = token.get("upn")
return UserInfo(application_id=application_id, object_id=object_id, upn=upn)