Admin - SSO, Authentication, and Authorization
Understand how Platform One manages Single sign-on (SSO), authentication, and authorization. Learn how applications can integrate and consume user profiles from any request coming into their application.
JWT/Keycloak Introduction
Mission apps are expected to use the Platform One Keycloak integration for their applications rather than standing up their own Keycloak private servers. The Platform One Keycloak is a layer abstracted in front of applications that is automatically integrated into every mission app. This means that no actions need to be performed to integrate with Keycloak from a development perspective. This means that Platform One and Party Bus have control over Keycloak and the addition of any users that may need to authenticate to mission applications. Therefore, if your application needs to expand its user base, then you will need to create tickets for login.dso.mil onboarding.
Additionally, Platform One Keycloak does not contain any public clients. Therefore, in order to connect the client secret and client id have to be known. We do not offer this information to customers as it is sensitive and there are no or few use cases where connecting directly to the client is necessary.
However, there is the question of being able to authorize users and control RBAC within an application. This can be done by parsing JSON Web Token (JWT) headers. Specifically, the Authorization request header. Information on this can be found below.
How Does the Auth Flow Work?
Here is a generalized workflow of how authentication and token validation is achieved.
What Does my App's Keycloak Group Hierarchy Look Like?
Every application is now using a standardized group hierarchy within Keycloak. Below is a high-level example for an application deployed to IL2:
Organization
⤷ Products
⤷ ApplicationName
⤷ IL2
⤷ development
⤷ collaborator
⤷ developer
⤷ production
⤷ roles
⤷ CUSTOMROLE1
⤷ CUSTOMROLE2
If deploying to multiple ILs, the same hierarchy will exist under IL4.
How Do I Get Users Added to My Keycloak Groups and Create Custom Roles?
To add users to the above hierarchy or ask for a custom role to be added to an IL, you can submit a Jira Service Desk (JSD) ticket using the General Support Form . Please submit a single ticket with a comprehensive list of users to be added and specify which groups to include them in, rather than submitting individual tickets.
How Can My App Integrate?
By default, all mission workloads deployed to Party Bus will automatically be configured to authenticate against P1 SSO. What does that mean?
- It is safe to assume every request coming in is authenticated against P1 SSO.
- It is safe to assume the token has been pre-validated against the SSO public key.
- It is safe to assume the user making the requests is authenticated for the Impact Level (IL) that your application is deployed to.
After authservice has successfully validated a request, it will set the Authorization: Bearer
header in the request that it passes into the application code. This header is in JWT format, can be parsed with any JWT library, and will contain the user's profile from Keycloak. Below is an example JSON that you can expect in that decoded header:
Decoded JWT:
{
"exp": 1613756062,
"iat": 1613755162,
"auth_time": 1613755162,
"jti": "abcd1234-ab12-cd34-ef56-abcdef123456",
"iss": "https://login.dso.mil/auth/realms/baby-yoda",
"aud": "client_id_here",
"sub": "abcd1234-ab12-cd34-ef56-abcdef123456",
"typ": "ID",
"azp": "client_id_here",
"nonce": "AbC01_AbCdEfGhIjKlMnOpQ12345678901234567890",
"session_state": "abcd1234-ab12-cd34-ef56-abcdef123456",
"acr": "1",
"email_verified": true,
"group-simple": [
"ADMIN",
"USER",
"ADMIN",
"Impact Level 2 Authorized",
"Impact Level 4 Authorized",
"Impact Level 5 Authorized"
],
"preferred_username": "john.doe",
"given_name": "John",
"activecac": "DOE.JOHN.P.1234567890",
"affiliation": "Contractor",
"group-full": [
"/Platform One/Products/Example1/IL2/roles/ADMIN",
"/Platform One/Products/Example1/IL4/roles/USER",
"/Platform One/Products/Example2/IL4/roles/ADMIN",
"/Impact Level 2 Authorized",
"/Impact Level 4 Authorized",
"/Impact Level 5 Authorized"
],
"organization": "Example Company LLC",
"name": "John Doe",
"usercertificate": "DOE.JOHN.P.1234567890",
"rank": "N/A",
"family_name": "Doe",
"email": "john.doe@example.com"
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
A few notes about the above:
- When a user meets the criteria for a specific IL, they are automatically added to the
Impact Level X Authorized
groups. - Both the
usercertificate
andpreferred_username
fields are unique across all users. activecac
is set when a user is logged in using their CAC, but not set when using MFA.- If you're using groups, it is highly advisable to use/parse the
group-full
field instead ofgroup-simple
. As you can see above, if someone is in the same role or group across multiple products, the group-simple won't capture that.
Here is also an example of an encoded HTTP header:
Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyY2VydGlmaWNhdGUiOiJET0UuSk9ITi5QLjEyMzQ1Njc4OTAiLCJyYW5rIjoiTi9BIiwiYWZmaWxpYXRpb24iOiJDb250cmFjdG9yIiwic2Vzc2lvbl9zdGF0ZSI6ImFiY2QxMjM0LWFiMTItY2QzNC1lZjU2LWFiY2RlZjEyMzQ1NiIsImF1ZCI6ImNsaWVudF9pZF9oZXJlIiwiYWN0aXZlY2FjIjoiRE9FLkpPSE4uUC4xMjM0NTY3ODkwIiwiZ2l2ZW5fbmFtZSI6IkpvaG4iLCJqdGkiOiJhYmNkMTIzNC1hYjEyLWNkMzQtZWY1Ni1hYmNkZWYxMjM0NTYiLCJlbWFpbCI6ImpvaG4uZG9lQGV4YW1wbGUuY29tIiwibm9uY2UiOiJBYkMwMV9BYkNkRWZHaElqS2xNbk9wUTEyMzQ1Njc4OTAxMjM0NTY3ODkwIiwicHJlZmVycmVkX3VzZXJuYW1lIjoiam9obi5kb2UiLCJpYXQiOjE2MTM3NTUxNjIsInR5cCI6IklEIiwic3ViIjoiYWJjZDEyMzQtYWIxMi1jZDM0LWVmNTYtYWJjZGVmMTIzNDU2IiwiZmFtaWx5X25hbWUiOiJEb2UiLCJuYW1lIjoiSm9obiBEb2UiLCJpc3MiOiJodHRwczovL2xvZ2luLmRzby5taWwvYXV0aC9yZWFsbXMvYmFieS15b2RhIiwiZW1haWxfdmVyaWZpZWQiOnRydWUsImFjciI6IjEiLCJncm91cC1zaW1wbGUiOlsiQURNSU4iLCJVU0VSIiwiQURNSU4iLCJJbXBhY3QgTGV2ZWwgMiBBdXRob3JpemVkIiwiSW1wYWN0IExldmVsIDQgQXV0aG9yaXplZCIsIkltcGFjdCBMZXZlbCA1IEF1dGhvcml6ZWQiXSwiZXhwIjoxNjEzNzU2MDYyLCJhdXRoX3RpbWUiOjE2MTM3NTUxNjIsImF6cCI6ImNsaWVudF9pZF9oZXJlIiwib3JnYW5pemF0aW9uIjoiRXhhbXBsZSBDb21wYW55IExMQyIsImdyb3VwLWZ1bGwiOlsiL1BsYXRmb3JtIE9uZS9Qcm9kdWN0cy9FeGFtcGxlMS9JTDIvcm9sZXMvQURNSU4iLCIvUGxhdGZvcm0gT25lL1Byb2R1Y3RzL0V4YW1wbGUxL0lMNC9yb2xlcy9VU0VSIiwiL1BsYXRmb3JtIE9uZS9Qcm9kdWN0cy9FeGFtcGxlMi9JTDQvcm9sZXMvQURNSU4iLCIvSW1wYWN0IExldmVsIDIgQXV0aG9yaXplZCIsIi9JbXBhY3QgTGV2ZWwgNCBBdXRob3JpemVkIiwiL0ltcGFjdCBMZXZlbCA1IEF1dGhvcml6ZWQiXX0.0tHxjGgtNDN90fnMQkf9dJxvah9WbhWzcW5gclleK0o
NOTE
If your application code uses the JWT
http header instead of the Authorization
header, please update it to use Authorization
. The JWT
header has been deprecated to save header size.
redirect-uri
Add the below to your staging or production url.
aka the DNS entry provided
oauth/callback
Example:
https://appname.staging.dso.mil/oauth/callback
PB Test Drive: AuthService Emulation for local development
Party Bus Test Drive is an ecosystem of tools that help you quickly create a development environment that closely resembles the Party Bus platform. This helps your project get off the ground fast and simplifies migration into the Party Bus environment.
Party Bus Test Drive helps your application by setting up a single-point https-enabled ingress and injecting a JWT on every request to your microservices - all in your local development environment. This emulates the Party Bus AuthService process so you can write code in dev that behaves the same in production and helps shorten the dev feedback loops.
TIP
Party Bus Test Drive can help you create new projects that are optimized for Party Bus using many common front-end and back-end tech stacks and databases.
UG - AuthService/JWT - Django Implementation
You can use Django as the backend for your REST API. It is essential to associate each user's request with their specific actions so that a mission commander can have a real-time overview of changes made to a mission. By implementing the authorization service, we can ensure that all users accessing the backend are authenticated through the Platform One SSO.
Decode the JWT for User Information
The approved way of receiving the user information is to decode the JWT that is passed through the Authorization header. For Django and Python we leverage PyJWT library.
JWT Decode Example
def decode_jwt(request):
encoded_auth_header = request.headers["Authorization"]
auth_header = jwt.decode(encoded_auth_header.split("Bearer ")[1], verify=False)
return auth_header
class PlatformOneAuthentication(authentication.BaseAuthentication):
def authenticate(self, request):
username = "AnonymousUser" # Default user
if "Authorization" in request.headers:
jwt_decoded = decode_jwt(request)
username = jwt_decoded["preferred_username"]
user = User.objects.get_or_create(username=username)[0]
2
3
4
5
6
7
8
9
10
11
12
What if the Group Structure Doesn't Meet My Requirements?
The authentication JWT will be present with every request, allowing application teams to use it solely for authentication purposes. If they require more detailed role or group-based authorization, they can handle that internally within their application code. Simply put, teams can store a user's roles and groups in their application database and use the authenticated user ID from the JWT to compare against those groups using their application code.