Try   HackMD

AS Lab 3 - (IAM) Identity and Access Management

Author: Fiege Polina

Task 1 - Preparation

Setup Keycloak

Install keycloak using docker image, run following command:

docker run -p 8081:8080 -e KEYCLOAK_ADMIN=admin -e KEYCLOAK_ADMIN_PASSWORD=admin quay.io/keycloak/keycloak:17.0.1 start-dev -Dkeycloak.profile.feature.upload_scripts=enabled

Make hostname sso point to 127.0.0.1:


Figure 1 - /etc/hosts

Access keycloak at sso:8081


Figure 2 - sso:8081

Create realm as_lab


Figure 3 - realm

Create sample user in this realm


Figure 4 - user

Launch sample app - installation instructions inside iam-lab-part1.zip

sudo apt install npm
npm install -g n
n stable

npm install --global yarn
yarn install
yarn dev


Figure 4 - app

Task 2 - Authentication and Single-Sign On

  1. Before you begin you must get familiar with terminology and concepts of OAuth 2.0 and OpenID Connect.

1. What is client?
Clients are entities that can request Keycloak to authenticate a user. An application or Internet site that the user uses and that interacts with the Authorization Server and Resource Server to obtain the user's private data.

3. What client types exist?
Confidential clients are clients that can keep the client_secret file confidential. Usually these clients are only applications (more often web applications) running on a developer-controlled server where the source code is not available to users.

Public clients cannot keep the client_secret file confidential, so the secret is not used for these applications. Both mobile apps and Javascript apps are considered public clients. Every time an application runs on a device under the user's control, it should be considered a public client.

4. What authentication flows exist?

The OAuth 2.0 Authorization Framework supports several different flows (or grants). Flows are ways of retrieving an Access Token.

  1. Authorization Code Flow - when the client is a regular web application running on the server.
  2. Implicit Flow - when client is a Single-Page App (SPA): an application running in a browser using a scripting language.
  3. Authorization Code Flow with Proof Key for Code Exchange (PKCE) - more recommended when client is SAP. Since the access token is not displayed on the client side, and this thread can return update tokens. Also used if the Application is a native app.
  4. Hybrid Flow combines the standard Implicit Flow with Form Post and standard Authorization Code Flow.
  5. Resource Owner Password Flow (should only be used when redirect-based flows cannot be used) - when client absolutely trusted with user credentials.
  6. Client Credentials Flow - this grant flow is suitable for machine-to-machine authentication where a specific user’s permission to access data is not required
  7. Refresh Token Flow - is specially used to gain new access_token from the Authorization Server by providing the refresh_token to the Token Endpoint.

5. Why is Authorization Code Flow preferred over the others?
Because we are interested to protect interactive clients (SAP and web-app) from against code substitution and in this case we need to use either a hybrid flow or PKCE should be used. If PKCE is available, this is a simpler solution to the problem.

Unlike providing an authorization code, implicit provision does not redirect the browser back to the backend of your application with an authorization code. Instead, it puts the access token directly into the URL as part of the redirect. Which leads to the danger of a code substitution attack. If we talk about the disadvantages of hybrid flow, they are as follows: can lead to leakage of additional (personally identifiable) data, all mitigation steps (for example, encryption) must be implemented by the client. This leads to a more complex implementation of the client library.

Authorization Code Flow with PKCE is already an official recommendation for
SPA.

6. What is Single-Sign On (SSO)?
This is an authentication method that allows users to securely authenticate to multiple applications and sites at once using a single set of credentials. In fact, SSO is part of a larger concept called Federated Identity Management, so sometimes SSO is referred to as a federated SSO. FIM simply refers to a trust relationship created between two or more domains or identity management systems. A SSO is a feature available within the FIM architecture.

7. What is the difference between OAuth 2.0 and OpenID Connect?
OAuth 2.0 is a special software platform that can also be considered part of the FIM architecture. OAuth focuses on trust relationships by providing user identification information to domains.

OpenID Connect (OIDC) is an authentication layer imposed on the OAuth 2.0 base to ensure the functionality of SSO.

  1. Setup authentication

Сreate corresponding client for app-pokemon:


Figure 5 - New client "app-pokemon"

Create a Role:


Figure 6 - New Role

Create a User in the Сredentials tab, the user needs to set a password:


Figure 7 - New User


Figure 8 - Connect Role with User


Figure 8 - Success authorisation

Then create the appropriate app-trainer client and show that SSO works. I took all the same steps as for app-pokemon.


Figure 9 - Success authorisation

  1. Analyze SSO workflow.

Take a look at full-login process and auto-login process in the network tab of browser devtools and describe what is happening. Use “Preserve log” to prevent resetting on redirects.

  1. What authentication flow is used?

It is the Authorization Code Flow.


Figure 10 - Browser Flow

  1. What is the difference between id_token and access_token?

After reviewing a large amount of information, this answer on the old forum seems to me the most human:

Source

The ID token confirms your identity, but does not give you permissions to manipulate resources. While the access token is associated with permissions and client accesses to the resource server.
The ID tokens are intended to be read by the OAuth client. Access tokens are intended to be read by the resource server.

For example user with its browser authenticate against an OpenID provider and gets access to a web application. The result of that authentication process based on OpenID Connect is the ID token, which is passed to the application as proof that the user has been authenticated.

In the OAuth 2 context, the access token allows a client application to access a specific resource to perform specific actions on behalf of the user. That is what is known as a delegated authorization scenario: the user delegates a client application to access a resource on their behalf.


Figure 11 - /openid-connect/token

  1. What is purpose of refresh_token?

The purpose of an update token is its ability to update a pair (the access token and itself). When the access token lifetime comes to an end, the application uses refresh token to update both tokens and continue using the new access token. The refresh token is one-time and often lives longer than the access token (if the access token lives 5 minutes in our application, then the time of the update token will be significantly longer)

The refresh + access token scheme limits the time for which an attacker can access the service. Compared to one token, which an attacker can use for weeks and no one will know about it.

  1. How is the session persisted? What will happen if you use incognito mode or another browser?

The session is saved by transmitting cookies such as, for example, the KC_RESTART cookie, which is created at the beginning of the authentication flow. It contains information about the client encoded in the JWS token. The cookie is used when the root authentication session expires and to create a new authentication session based on the client information provided in the cookie. Further, through mitmproxy, you can see that the token is loaded immediately upon a new logging attempt. if you switch from the main application to the Pokemon application every time, for example, and click on the "log in" button (not to log out, but just close the tab), then mitmproxy will constantly collect such calls:


Figure 12 - Persisted session

In the new session, everything is as in the picture, there are a lot of calls to the keycloak, getting a new token, also setting cookies.


Figure 13 - New session

Resource access with role-based authorization

  1. Enabling authorization. In this part you will setup simple role-based authorization.

4.1 Keycloak issues access tokens in JWT format. The advantage of JWT token is that all information that is required to make a decision about authorization can be extracted and verified from it.

1. What is the format of JWT token? How can you decode it, is there any standard tools?
As I understood from the header above, you are asking me about access tokens (not about the ID token). In this case, I will answer you that the Bearer Token format is used.

Bearer Tokens are the predominant type of access token used with OAuth 2.0. The basic OAuth 2 specifications say nothing about the format of the access token. It can be a string of any format. In our case, it's JWT, okay. In simple words, JWT is just a string in the following format header.payload.signature.


Figure 14 - Access Token

As for standard methods, perhaps you mean to do it directly with Keycloack tools. We use any Base64 decoder for decoding. In any case, here is a very comprehensive answer about the ways of researching this token.

2. How is JWT token issued and verified?
First, the user logs into the authentication server using an authentication key (for example, a login/password pair). The authentication server then creates a JWT and sends it to the user. When a user makes a request to the application API, he adds the previously received JWT to it. In this moment the application can check by the JWT passed with the request whether the user is who he claims to be. This happens as follows: the application server receives a secret key from the authentication server during the installation of authentication processes. Since the application knows the secret key when the user makes an API request with a token attached to it, the application can repeat the signing algorithm to the JWT. The application can then verify this signature by comparing it with its own, calculated by hashing. If the signatures match, then the JWT is valid, that is, it came from a verified source.

3. What is claim and what is scope?
Assertions are a payload of a name/value pair that contain information about the user. Scope is the scope of the token, which determines the possibilities of its use in relation to user data. Each scope returns a set of user attributes, which are called claims. The scopes an application should request depend on which user attributes the application needs. For example, you can use a token with scope: profile email openid to send a personalized welcome letter to the user.

4. What is aud claim?
One important claim is theaud claim. This claim defines the audience of the token, i.e., the web application that is meant to be the final recipient of the token. This claim is only in the ID token.


Figure 15 - theaud claim

4.2 Look at how the api-pokemon makes authorization decision and list the critical claims that are required for positive decision.
File: server/verify-access.ts


Figure 16 - verify-access.ts

First of all, we need to make sure that in addition to the Bearer type, the token also contains the necessary: we check the header

const token = header.substring(7)

Actually, below, in the try handler, you can see how the check itself happens with this line:

jwt.verify(token, secretOrPublicKey, [options, callback])

(Synchronous) If a callback is not supplied, function acts synchronously. Returns the payload decoded if the signature is valid and audience are valid. Next comes the recognition of the payload, which is an service role. It can be seen from the code that the most critical thing in the payload is the presence of roles, or if be more correct at least one allowed role.

Critical claims that are required for positive decision:

  1. algorithms: ["RS256"]
  2. audience: service
  3. client roles (service) (resource_access.${service}.roles)
  4. allowedRoles (roles) (User accessing the service has to have at least one role to be permitted the access)

4.3 Create corresponding clients and add roles

I found the specified roles in the file along the path:

iam-lab-part1-main/pages/api/pokemon/[name].ts


Figure 17 - Roles

After that I created a new client api-pokemon. Also Keycloak provides a special bearer-only type of client - it is for services that do not initiate user login.


Figure 18 - New client

And added two roles "editor" and "readonly"


Figure 19 - New roles

Note that for app-pokemon you already have associated client in Keycloak. In this case, I already have a ready-made user for this client.


Figure 20 - Role Mappings

Make changes to Keycloak such that correct required claims are included into access token. Also, for debugging purposes Keycloak’s Admin console provides Evaluation tool that shows you what is included inside access token (I will use it later).

For valid JWT verification do not forget to replace hardcoded cert (in server/verify-access.ts) with the cert of your realm.


Figure 21 - Cert of my realm

Show that app-pokemon successfully works.



Figures 22,23 - Editor & Readonly

a) What are realm roles and client roles in Keycloak?

Realm-level roles are in global namespace shared by all clients. Client roles have basically a namespace dedicated to a client.

b) What is a composite role?

Any realm or client level role can be turned into a composite role. A composite role is a role that has one or more additional roles associated with it. When a composite role is mapped to the user, the user also gains the roles associated with that composite.

c) How does browser-side app app-pokemon understand that form input should be enabled/disabled?

I think the browser side checks the access token, in which it detects a link to the resources of a certain role. I've looked through all the application files, and it seems to me that the mapping going is just by name. For example, if the editor role has an IsEditable variable, then it is assigned to it at the java config level, and therefore I did not immediately understand why I could not change this or that access to the Pokemon profile directly from the keycloak.


Figure 24 - Evalueting tool

  1. Issuing fine-grained access token
    By default Keycloak includes all available user roles from all clients into the access token. Considering least privilege principal, that should be fixed.

5.1 Create another test-client with some-role and add this role to the sample user. After that inspect access_token token for app-pokemon. Is new role automatically included into it?

I have created a new client with a test role. Then I gave the user a Bulbosaurus role for this client.




Figures 25, 26, 27 - Set up

As you can see, the access token of Bulbasaurus to the Pokemon application displays all the clients from whom he owns any role.


Figure 28 - Access token

5.2 Learn how exactly user information that Keycloak possesses is mapped inside to access token. Make changes to Keycloak such that for app-pokemon only api-pokemon roles are mapped to the access token, even if he has other roles.

To change this default behavior, you must explicitly turn off the Full Scope Allowed switch and declare the specific roles you want in each individual client.


Figures 29, 30 - Set up & Result

a) How is claim added to access token?

The default profile service of ASP.Net Identity searches for all user claims from the database storage. The profile service will use cookie claims (issued by the server during the authentication process) to generate access token claims when the client requests an access token by providing claims from the cookie

In other case, you can simply turn to the Client Scopes tab and see what user data the access token carries with it. These scopes are defined globally for all clients, there are those that are used by default, and there are optional ones. We can also create our own global scopes. For example, I can use the user's banal email address (because it is defined by default in the user's credentials).


Figures 31, 32 - Client Scopes

  1. Custom scopes
    Keycloak allows you to create your custom scopes to include additional information to access token, for example custom user attribute.

Make changes to Keycloak such that access token for issued for app-pokemon will include favorite_color user attribute.

To do this, I need to go to the client, select the Mappers tab, and create a new favorite_color mapper in it. I am creating it exclusively for the app-pokemon, this mapper will not be displayed to other clients. After that, I need to create an attribute associated with this mapper from the user himself.


Figure 33 - New mapper

I can also choose which type of token this claim will be displayed in.


Figure 34 - New attribute

As you can see, this claim is now present in the token of this user, although it is not information from the global client scopes.


Figure 35 - Result

References:

  1. The OAuth 2.0 Authorization Framework
  2. Authentication and Authorization flow
  3. Authentication flows
  4. Keycloak documentation: Client Scope