Modern A&A

Authentication and Authorization
oAuth2 and OpenID Connect (OICD)

An simple introduction to a endless complex topic

Equinor #AppSec community

Objectives

Workshop objectives

De-mystify, build confidence and prepare for further exploration of A&A

Highlights

  • Give an introduction to the basics of modern web A&A
  • Explore RFC (specs) and Azure Implementation
  • Code a few A&A scenarios
  • Insights into threats and security best current practices (BCP)

Workshop Outline

Workshop outline

  • Which problems are we trying to solve?
  • Practicalities
  • The basics of A&A
  • Exercises (10+1)
  • Raw flows, add authentication to web app, using frameworks & libraries, accessing 3rd party api, refresh tokens, single page web app (SPA), PKCE, protecting web api's and On-Behalf-Of flow.
  • Deploy application to the Cloud (using Radix)

A day in the life of

sMailandStuff

The mature web Swiss Army Knife

sMailandStuff on Radix

The players

The delegation problem

Giving access to 3rd parties

API's are a driving force

Old style A&A

Impersonating, Direct Authenticating

Old style A&A

Impersonating, Direct Authenticating
  • Store id/password for each service
  • No way to revoke access
  • Access not time limited
  • Full access only - not granular

New Style A&A

Delegating

New style A&A

  • Id/password not stored on client
  • Access can be revoked
  • Access can be time limited
  • Access can be granular
  • Access is delegated from resource owner to client

Disclaimer

The more I learn about the topic at hand, the more I realize how complex it is. I am not an expert. Very rarely is the answer black and white. Context is important. I assume that quite a few of you have experience, insight and knowledge to share. Please share! Sharing is caring!

Code examples are not production quality - they are happy-path

Practicalities

#appsec-authentication-and-authorization-course

on Slack

Useful links

Run-time environments -
known differences

  • Examples uses Unix path notation "./src".
    In Windows this will be "src/
  • Scripts in course code, like npm start uses Linux notation. Must be changed for Windows environments

The basics of A&A

Part #1

Authentication vs. Authorization

Authentication =
is the mechanism to verify the identity of a user

Authorization =
is the mechanism to verify access to a resource

oAuth2

The OAuth 2.0 authorization framework enables a
third-party application to obtain limited access to an HTTP service,

either on behalf of a resource owner
by orchestrating an approval interaction between the resource owner and the HTTP service

or by allowing the third-party application to obtain access on its own behalf.
oAuth2 is a delegation protocol, a means of giving someone who controls a resource the capability to delegate access to the resource on their behalf (without impersonating).

oAuth2 vs OpenID Connect

  • oAuth is for delegation, the goal is to access api's
    • To get a ticket (token) which gives access to a protected resource
  • OpenID Connect is an identify layer on top of oAuth
    • Answering key question: Who is logged in?
    • Defines user authentication metadata
    • Can control authentication
    • Supports federation

oAuth2 Roles/Actors

resource owner
An entity capable of granting access to a protected resource. When the resource owner is a person, it is referred to as an end-user.

resource server
The server hosting the protected resources, capable of accepting and responding to protected resource requests using access tokens.

client
An application making protected resource requests on behalf of the resource owner and with its authorization. The term "client" does not imply any particular implementation characteristics (e.g., whether the application executes on a server, a desktop, or other devices).

authorization server
The server issuing access tokens to the client after successfully authenticating the resource owner and obtaining authorization.

Actors

Abstract protocol flow (rfc6749)

+--------+                               +---------------+
|        |--(A)- Authorization Request ->|   Resource    |
|        |                               |     Owner     |
|        |<-(B)-- Authorization Grant ---|               |
|        |                               +---------------+
|        |
|        |                               +---------------+
|        |--(C)-- Authorization Grant -->| Authorization |
| Client |                               |     Server    |
|        |<-(D)----- Access Token -------|               |
|        |                               +---------------+
|        |
|        |                               +---------------+
|        |--(E)----- Access Token ------>|    Resource   |
|        |                               |     Server    |
|        |<-(F)--- Protected Resource ---|               |
+--------+                               +---------------+
						

Abstract protocol flow

+-- Resource --+ +-- Client -- + +- Authorization -+ +-- Resource --+
+    Owner     + +             + +     Server      + +   Server     +
+--------------+ +-------------+ +-----------------+ +--------------+
     -                   -                -                     -
     |  (A)Client request|                |                     |
     |      Authorization|                |                     |
     |<------------------|                |                     |
     |- - - - - - - - - - - - - - - - - ->|                     |
     |                   |                |                     |
     |(B) Resource Owner |                |                     |
     |Grants authorization                |                     |
     |----------------------------------->|                     |
     |                   |<- - - - - - - -|                     |
     |                   |                |                     |
     |                   |(C) Client send |                     |
     |                   |  Authorization |                     |
     |                   |          grant |                     | 
     |                   |--------------->|                     |
     |                   |                |                     |
     |                   | (D)Autorization|                     |
     |                   |    server sends|                     |
     |                   |    access token|                     |
     |                   |<---------------|                     |
     |                   |                |                     |
     |                   |(E)Client sends |                     |
     |                   |Access Token    |                     |
     |                   |------------------------------------->|
     |                   |                |                     |
     |                   |                |(F)Protected resource|
     |                   |                |       sends resource|
     |                   |<-------------------------------------|
     |                   |                |                     |
     -                   -                -                     -                                   
						

What oAuth is and is not

  • Is not defined outside HTTP
  • Is "requiring" TLS
  • Is not an authentication protocol
  • Is not processing authorization
  • Is not defining user-to-user delegation
  • Is not defining a token format
  • Is not defining crypto methods
  • Is not a single protocol -
    it supports multiple use cases -
    it's a protocol for protocols

Obtaining authorization -
the oauth Dance

To request an access token, the client obtains authorization from the resource owner. The authorization is expressed in the form of an authorization grant, which the client uses to request the access token. OAuth defines four grant types: authorization code, implicit, resource owner password credentials, and client credentials. It also provides an extension mechanism for defining additional grant types.

It's about getting tokens

  • Access token (to provide access)
  • ID token (to prove identity)
  • Refresh token

More on tokens later....

Authorization Code Grant

rfc6749 #4.1

+----------+
| Resource |
|   Owner  |
|          |
+----------+
 ^
 |
(B)
+----|-----+          Client Identifier      +---------------+
|         -+----(A)-- & Redirection URI ---->|               |
|  User-   |                                 | Authorization |
|  Agent  -+----(B)-- User authenticates --->|     Server    |
|          |                                 |               |
|         -+----(C)-- Authorization Code ---<|               |
+-|----|---+                                 +---------------+
|    |                                           ^      v
(A)  (C)                                         |      |
|    |                                           |      |
^    v                                           |      |
+---------+                                      |      |
|         |>---(D)-- Authorization Code ---------'      |
|  Client |          & Redirection URI                  |
|         |                                             |
|         |<---(E)----- Access Token -------------------'
+---------+       (w/ Optional Refresh Token)			
					

Authorization Code Grant

Authorization Code Grant

-1-

Client via user agent - initiates

Authorization Code Grant

-2-

GET /authorize?
client_id=client
&scope=(optional)
&reponse_type=code
&state=1234 &redirect_uri= https://app/callback

Authorization Code Grant

-3-

Authentication is handed over to authentication server

Authorization Code Grant

-4-

303 redirect https://app/callback?
code=o-t-c
&state=1234

Authorization Code Grant

-5-

POST /token grant_type=authorization_code
&client_id=
&client_secret=
&code=
&redirect_uri=

Authorization Code Grant

-6-

{
"access_token":"2YotnFZFEjr1zCsicMWpAA", "token_type":"Bearer", "expires_in":3600, "refresh_token":"tGzv3JOkF0XG5Qx2TlKWIA"
}

OpenID Connect (OICD)

  • Identity layer built on-top of oAuth2
  • Answer to the "Who is logged in?" question
  • Defines user authentication meta data
  • Can control authentication
  • Enables federation
oAuth2 term OICD term
Resouce owner User
Client Relying party
Authorisation server, Protected resource Identity provider

OpenID Connect Code Flow

-2-

GET /authorize?
client_id=client
&scope=read+openid
&reponse_type=code
&state=1234 &redirect_uri= https://app/callback

OpenID Connect Code Flow

-3-

Authentication is handed over to authentication server

OpenID Connect Code Flow

-4-

303 redirect https://app/callback?
code=o-t-c
&state=1234

OpenID Connect Code Flow

-5-

POST /token grant_type=authorization_code
&client_id=
&client_secret=
&code=
&redirect_uri=

OpenID Connect Code Flow

-6-

{
"access_token":"ey2YotnFZFEjr1zCsicMWpAA",
"token_type":"Bearer",
"id_token": "eynndj3nn77hs7Hhjhjh" ,
"expires_in":3600,
"refresh_token":"tGzv3JOkF0XG5Qx2TlKWIA"

}

OpenID Connect (OICD)

  • New IDToken received upon successful authentication and serves as proof of who's authenticated
  • Access tokens are not proof of authentication. They are not intended for client - rather the protected resource
  • IDToken's can be given to client along with Access tokens
  • IDTokens' are signed JWT tokens.
  • ID tokens contains claims such as
    • iss - issuer of the token
    • sub - subject - user id from identity provider
    • aud - audience - id for relying party
    • exp - expiration time stamp
  • For the Azure implementation, more documentation on the Microsoft Identity Platform doc pages. Explore attributes such as "prompt", "login_hint", "response_mode"

OAuth Flows that we have not covered

  • Client credentials
    Typically service to service in protected environment
  • Resource Owner Password Credentials
    High trust envionments where the resource owner trusts it's credentials to the client
  • (Implicit grant will be covered later)

Please note ...

  • Use Azure AD v2 endpoints whenever possible, V1 is about to be deprecated
  • Be aware of doc and v1 vs. v2 (it's easy to read the wrong one)

Exercise - 1

Raw Authorization Code Grant

Exercise Outline

  • Clone github repository
  • Investigate spec and doc on Azure
  • Register app object in Azure AD
  • Set-up postman
  • Request authorization code
  • Request an access token
  • Explore tokens

Clone github repository

https://github.com/larskaare/WebAuthAuthorAndOtherCreatures

git clone git@github.com:larskaare/WebAuthAuthorAndOtherCreatures.git

Register application in Azure AD

  • Navigate to portal.azure.com and find Azure Active Directory
  • Select App registrations
    (App registration vs. Enterprise Applications
  • Register new application
    • Activate "Application developer role" in "Privileged Identiy Management"
    • Name: (inital)-(aa-client) or something else
    • Type: Single tenant
    • Redirect uri: http://localhost/auth
  • Explore options for the new app registration

Set-up Postman

  • Start Postman
  • Import "Azure AD v2.0 Protocols.postman_collection.json" from "./ex-1" folder

Request authorization code

  • Select "Oauth 2.0 Authorization Code Flow" -> GET Autorization request
  • Explore "endpoints" for application registration (Azure Portal)"
    • Copy and substitute oAuth2 Authorization endpoint v2 to GET request
    • Copy "client_id" to GET request parameter
    • Change "redirect_url" to "http://localhost/auth" for GET request parameter
  • Look at scope for GET request. It's OICD? RFC says optional, Azure AD says mandatory.
  • Copy the GET request to clip board and execute from web browser
    (the code is use once within seconds)
  • Copy authorization code from "code" parameter in the browser response

  • Explore changig "scope" and convert to "native" oAuth2 request
  • Why do we have to execute request in web browser?
  • Discuss security considerations
  • Good practice : remove the localhost redirect from production applications

Request an access token

  • Select "POST - Token Request - Auth Code" from Postman collection
  • Copy and substitute oAuth2 Token endpoint v2 to POST request
  • Define client secret for application in Azure Portal
  • Update body for POST request client_id, redirect_uri, client_secret, code
    (code is from the GET request)
  • Send POST request
  • Explore response
  • Discuss security considerations (SSL, secrets, certificates, public vs. confidential client)

Explore tokens

  • Use https://jwt.ms to explore tokens
  • Explore tokens, claims and dates
    (access_token, refresh_token, id_token)
  • Experiment with scope param
    Scope profile+email will put "more" info into id_token
    Scope offline_access will add refresh_token
  • Discuss claims, optional claims, application manifest and token config in AD app object
    • Standard claims in JWT tokens (RFC 7519)
    • Registry for public claims to avoid naming conflicts - IANA
    • Standard OICD JWT Token claims (1.0)
  • Discuss security considerations (token validation, token storage)
  • Good practice: Don't uses access tokens as proof of authentication. Access tokens are for the protected resource

Exercise 2

Web applicaton

Getting an access token

Outline

  • Prepare environment (ex-2)
  • Environment Variables
  • Explore the web app code
  • Config, run and explore app
  • Secrets
  • Staging environments and logging

Preparing the environment

  • Navigate to the ./ex-2 directory
  • Install dependencies $ npm install

Environment variables

  • Define environment variables $ export PORT=3000 $ export CLIENT_SECRET=[your secret] $ export CLIENT_ID=[your client id] $ export NODE_ENV=[production | developement | debug]
  • Good practice: Move config into config files, potentially .env files (that are defined in .gitignore and/or kept outside version control, stored outside git).

    The dotenv module is one option in the NodeJs world.

Explore the code

  • Explore endpoints in Azure for application object
  • Explore application config objects
    (authServer, client, scope) in ./app.js
  • Explore authentication code in ./app.js
    • /authorize
    • /callback
  • This example uses basic auth for passing client credentials (remember to base64 encode)
  • (This example uses the request module - which is deprecated by February 2020)
  • Explore routing/views in application

Config, Run and Explore

  • Configure the authServer object in app.js
  • Explore the client object in app.js
  • Configure environment variables
  • Verify the app object in Azure AD
    (Hint: redirect URI's)
  • Run web application $ npm start
  • Explore spec, alter scope and other params
  • Explore what consent you have given to apps on Azure AD.
    Test revoking for test app.
  • Explore running the app with NODE_ENV=debug
  • Bad practice: Extracting things like "given_name" from Access Token to display in client (as done in exercise code)

Secrets

  • Good practice: Keep secrets outside version control!
  • Ok practice: Inject secrets as environment variables
  • Good practice: Store secrets in keyvaults (explore if managed identities are available (MSI))

Staging environments - logging

  • Explore logging logic in ./app.js
  • Different logging level dependent on environment (debug, development, production)
  • Good practice: Have a strategy for log purpose and transports (why you log, where you store/not store)
  • Good practice: Be conscious of what you put in log files!!

The basics of A&A

Part #2

Let's disucss a few elements

Clients

  • Clients are either confidential or public
    • Confidential: Clients capable of maintaining the confidentiality of their credentials. (Web apps)
    • Public: Clients incapable of maintaining the confidentiality of their credentials (SPA, Native)
  • Clients provide a redirection URI

Protocol Endpoints


    Authorization endpoint: used by client to get authorization from resource owner,
    user is involved - delegation
  • Token endpoint: used by client to exchange authorization grant for an access token
  • There may be other endpoints based on specific implementation, OICD has a few more as well.

Channels - Interaction between actors

  • Front-channel: Communication between two parties through an intermediate (the web browser)
  • Back-channel: Communication happening outside the view of the resource owner and the user agent (like browser)

Tokens

  • Token type: How it can be used
    • Use it as is, bearer type (Access token) (RFC6750)
    • Use it, but prove that I own it
      (Proof Of Possession)(No wide implementation)
  • Token format: Encoding
    • By value (token contains all values)
    • By reference (pointer to more information)
  • Token purpose: Who is it for?
    (Client, Authorisation Server, Resource Server

Access token

  • Access tokens are credentials used to access protected resources. An access token is a string representing an authorization issued to the client. The string is usually opaque to the client. Tokens represent specific scopes and durations of access, granted by the resource owner (or admin), and enforced by the resource server and authorization server.
  • By reference or value, for resource server, bearer type

Refresh token

  • Refresh tokens are credentials used to obtain access tokens. Refresh tokens are issued to the client by the authorization server and are used to obtain a new access token when the current access token becomes invalid or expires, or to obtain additional access tokens with identical or narrower scope (access tokens may have a shorter lifetime and fewer permissions than authorized by the resource owner). Issuing a refresh token is optional at the discretion of the authorization server. If the authorization server issues a refresh token, it is included when issuing an access token.
  • By value, for client

ID token

  • ID tokens are issued to the client to validate that a user is who he/she claims to be and to provide additional information about the user.
  • ID tokens are issued as part of OpenID connect
  • By value, for client

Azure AD (AAD) issues JWT tokens (access, id)

JSON Web Token (JWT)(RFC7519)
eyJ0eXAiOiJKV1QiLA0KICJhbGciOiJIUzI1NiJ9.
eyJpc3MiOiJqb2UiLA0KICJleHAiOjEzMDA4MTkzODAsDQogImh0dHA6Ly9leGFtcGxlLmNvbS9pc19yb290Ijp0cnVlfQ.
dBjftJeZ4CVP-mB92K27uhbUJU1p1r_wW1gFWFOEjXk


{
"typ": "JWT",
"alg": "HS256"
}.
{
"iss": "joe",
"exp": 1300819380,
}.
[Signature]
			 
			
Header, Payload with claims and Signature - based64 encoded

Example ID Token

Azure AD ID Token claims

{
"typ": "JWT",
"alg": "RS256"
}.{
"aud": "cab2507d-e7d1-46fd-9580-ea7de0cd02ea",
"iss": "https://login.microsoftonline.com/../v2.0",
"exp": 1571657734,
"name": "Jon Doe",
"oid": "..",
"roles": [
"Admin"
],
"sub": "..",
}.[Signature] 
			

Scope

  • Defined the scope of access
  • Defines permissions given in the access token
  • Consentable
  • The scope request is configured on the client
  • The Scope is requested in the flow
  • The Authorization Server determines if scope should be issued

Consent

  • Scope can be consented by (In Azure impl)
    • User on on-behalf of self
    • Admin on behalf of organization
  • The consent is about delegating the client access to resource server on a users behalf

Token Introspection

  • The process for a protected resource to query the authorization server to verify validity of a oAuth2 token
  • An extension to oAuth2 defined in rfc7662
  • Getting tokens type by ref and querying for "details"
  • Not currently supported by Azure AD (Improvement request)

Exercise 3

Scope

Consent, Graph explorer, tokens - security, state - session

Outline

  • Explore the MS Graph Explorer
  • Discuss Permissions and Consent
  • Prepare environment (ex-3)
  • Explore the code
  • Config, run and explore
  • Security considerations - good practices++

The MS Graph Explorer

  • Open the MS Graph Explorer
  • Sign in
  • Query the /v1.0/me endpoint
  • Query the /v1.0/me/memberOf endpoint
  • Query the v1.0/me/mailFolders('Inbox')/messages?$select=sender,subject endpoint
  • Explore the graph api documentation
  • Play around with other endpoints, filtering, permissions, consent

Permissions & Consent

  • Documentation of Permission and Consent on the MS Identity platform
  • Scope = requested permissions
  • Delegated permissions, for signed-in-user, user or admin consent
  • Application permission, without signed-in-user, admin consent only
  • Effective permissions - least privileged between app and user (Example App has User.ReadWriteAll, User has no admin right = Effective rights will be only to update own profile)
  • Effective permission for application permission will be the full permission

Preparing the environment

  • Navigate to the ./ex-3 directory
  • Install dependencies $ npm install

Explore the code

  • Explore authentication code in ./app.js
  • Adding new route to show mail (/routes/mail.js)
  • Adding capabilities to scope (Mail.Read)
  • Storing access_token in session
  • Explore routing/views in application (app.use('/mail', mailRouter);)

Config, Run and Explore

  • Explore the authServer object in app.js
  • Explore the client object in app.js
  • Configure environment variables
  • Run web application $ npm start
  • Explore the new mail functionality

Security considerations

  • Access_token storage
  • Increase user experience - extend session management to persist user data, refresh tokens??
  • Access_token validation - is not happening
  • oAuth2 Threat Model and Security Considerations
  • OAuth Security Topics
  • Good practice: It's a lot of hard work to get A&A done properly - USE a Framework!
  • Good practice: Protocols (and Frameworks) does not guarantee security, Developers Do
  • Good practice: Only request the minimum scope, dynamically - not all at once

Exercise 4

Use frameworks!

Outline

  • Explore available frameworks for oAuth2
  • Prepare environment (ex-4)
  • Explore the code
  • Config, run and explore
  • Font-end vs. back-end communication channels
  • Session handling
  • Security considerations - good practices++

Frameworks

Preparing the environment

  • Navigate to the ./ex-4 directory
  • Install dependencies $ npm install

Explore the code

  • Introducing passport.js
  • Introducing passport-azure-ad
  • config/config.js
  • ./src/
    • app.js
    • authutils.js
    • logHelper.js
  • ./routes/
    • index.js
    • mail.js
    • userinformation.js

Config, Run and Explore

  • Update the AD application object with new redirect url
  • Configure environment variables
  • Run web application $ npm start
  • Explore the application
  • Change "node_env" and observe whats happening to the logging

Font-end vs. back-end com. channels

  • Font-end: Browser (User agent) to
    • back-end (localhost:3000/mail,
      /userinfo)
    • Azure AD authentication
  • Back-end: Client (Web app) to
    • Azure ADd authorize (getting access token)
    • Accessing the MS Graph on behalf of user
  • A tool like Burp Community Edition could be used to investigate/debug front-end and back-end traffic when on localhost Browsers may have different policies on using proxies for localhost

Session handling

  • We are using OIDC and the ID TOKEN as proof of authentication and to drive the user experience/mgmt in our app
  • OICD offloads a lot of user management for our app
  • Our web application use express and express-session to manage user session
  • The session cookie is named connect.sid
  • The cookie only stores session id
  • The cookie is signed (to detect tampering)
  • Session data is stored on the back-end (memory, not recommended for production)
  • Task: Open the developer tools in the browser and locate the session cookie for our app. Alter cookie and observe effect in app

Security considerations

  • Token storage
  • Persistent Session storage (from memory to database?)
  • Cookie signing keys
  • Cookie stealing
  • Access_token is being validated
  • Only authenticated users are getting access to end-points (ensureAuthenticated)
  • Good practice: Follow security advices for all frameworks (Example: Express - Production Best Practices: Security)
  • Good practice: Know your frameworks - it takes time & capacity when complexity is hidden!

Exercise 5

Authorization scenarios

The Application Manifest

Outline

  • Prepare environment (ex-5)
  • Explore the code
  • Config, run and explore
  • Scenario 1: Only people with valid account should have access
  • Scenario 2: Only defined users/groups should have access
  • Scenario 3: Application roles to handele authorisation
  • Accessing 3d party api's protected by oauth2

Preparing the environment

  • Navigate to the ./ex-5 directory
  • Install dependencies $ npm install

Explore the code

  • src/app.js
    • passport.use(....)
      Creating authInfo object in profile to store relevant claims
  • view/userinfo.pug
    • Showing information about groups & roles in claim

Exploring claims in tokens


{...}.
{...
 "name": "Jon Doe",
 "preferred_username": "",
 "roles": [
	"Writer"
 ],
 "groups": ["",""],
}.[Signature]
								
Explore ID Tokens and Acess Tokens and in MS Identity platform as well as the optional claims (and the new token configuration in the AD app object).

(Claims does not always show up in the token you expect. OIDC drives some claims into the ID token)

Config, Run and Explore

  • Verify the AD application object redirect url
  • Configure environment variables
  • Run web application $ npm start
  • Explore the "user information" part of the web application

Scenario 1:
Only people with a valid account should have access

  • App Registration (object) vs. Enterprise Application (instance, multi-tentant)
  • In "Enterprise Applications" (Azure AD) explore the property section for your application
    • "Enables for users to sign-in?"
    • "User assignment required?"
      (User must be assigned to be able to sign in)
  • Sign-in enabled and no user assignment required = available to everyone with valid user account in tenant

Scenario 2:
Only defined users/groups should have access

  • There are several ways to achive this scenario
  • 1) Managing the App Object
    • Set "User assignment" to "Yes" - in App property
    • Add users and groups in "Users & Groups" - in App property
  • 2) Alter application manifest to include security groups
    • The Application Manifest defines all the attributes and behavior of an applicaton object
    • groupMembershipClaims to include "SecurityGroup"
    • Alter - save - explore "user information part in our web app
    • This approach have some limitations (size)
  • 3) Read information in the Microsoft graph about user & groups. This require admin concent for the application and generally gives to much privileges!! Should be avoided

Scenario 3: Application roles

  • Application roles implement RBAC
  • App admins grant permissions to roles, users and groups are assigned to roles
  • Define application role in app manifest (doc)
    ID is a self generated GUID and must be unique (Online GUID Generator)
  • 
    "appRoles": [
    {
      "allowedMemberTypes": ["User"],
      "displayName": "Writer",
      "id": "b421319c-3e45-4685-aaf2-b1282ad05a6f",
      "isEnabled": true,
      "description": "Writers Have the ability to create tasks.",
      "value": "Writer"
    }
    ],
    "availableToOtherTenants": false,
    											
  • Alter manifest with "Writer" app role". Save
  • Assign a user or group to the "Write roles" in "Enterprise apps" - "Users and Groups"
  • Explore the "User information" part of our web app

Accessing 3d party api's protected by oAuth2

  • Add/Include api resource to scope
  • Hit token endpoint to request an access token
  • Use access token to access api
  • Explore the mail part of our web application (/routes/mail.js)
  • Explore Static vs. Dynamic permissions
    • Permissions and Consent in MS Identity
    • Change scope to include https://graph.microsoft.com/Contacts.read from code (scope config) and/or "api permissions" in app definition (AD)
    • Remember to restart app after changes (and do a new login)
    • Add other resources from the MS Graph Explorer and observe consent flow

Exercise 6

Refresh tokens

Outline

  • What are refresh tokens?
  • Framework support for handling refresh
  • Prepare environment (ex-6)
  • Explore the code
  • Config, run and explore

What are refresh tokens?

  • rfc6749 section 1.5, rfc6749 section 6 for refresh access token
  • "Refresh tokens are credentials used to obtain access tokens."
  • Are used to get new access token when current one expire
  • Are used to get new access token to narrow scope
  • Refresh tokens are issued by the authorization server and are never used by resource servers
  • Refresh tokens is only issued to secure clients
    (Not supported by implicit flow)
  • Refresh tokens can be stored on back-end to perform operations on behalf of user when not logged in
  • Refesh tokens are quite often about user experience
    (log-in experience)

Framework support for handling refresh

  • Framework support for automatic handling of refresh tokens is varying
  • Verify support in each framework
  • Flows that emits refresh tokens in Azure
  • Single Page Web applications using MSAL.JS usually do a silent login-and-get-new tokens to the user due to no refresh token
  • The framework we use, Passport.js, does not have native support for refresh tokens. So lets add it :)

Preparing the environment

  • Navigate to the ./ex-6 directory
  • Install dependencies $ npm install

Explore the code

  • config/config.js
    • Scope param includes "offline_access" which emits refresh token
    • "diffSecondsBeforeRefresh" (ExpireTime - NowTime <= diffSecondsBeforeRefresh)
  • src/app.js
    • Storing refresh-token in authinfo object
    • Middleware (considerRefresh) to determine if we should get new access tokens
  • src/authutils.js
    • "considerRefresh" function which does the magic
    • We refresh based on time (in seconds) before expire
    • We could also react to the 401 issued by Azure AD when we try to use and expired access token
    • (It's worth knowing that java script stores time in milliseconds while it's seconds int the tokens)

Config, Run and Explore

  • Verify the AD application object redirect url
  • Configure environment variables
  • Run web application $ npm start
  • Explore the "user information" part of the web application
  • Explore changing the "diffSecondsBeforeRefresh" config and observe token refresh (by expire date and in log)
  • Observer that we get a new access token with the refresh, but the "old" one is still valid

Exercise 7

Single Page Web Application (SPA)

Implicit grant flow

Outline

  • What is a SPA?
  • Implicit grant
  • Prepare environment (EX-7)
  • Explore code
  • Config, Run and Explore
  • Security considerations

What is a SPA?

  • SPA = Single Page Application
  • Re-Writing DOM rather than refreshing page
  • 1) Web browser (user agent) only
    (all communications happens
    in browser, client is in browser)
  • 2) Hybrid, web communicates
    to dedicated back-end (client)
    which then handles external
    communication

oAuth2 Implicit Grant

rfc6749 #4.2
		+----------+
		| Resource |
		|  Owner   |
		|          |
		+----------+
			 ^
			 |
			(B)
		+----|-----+          Client Identifier     +---------------+
		|         -+----(A)-- & Redirection URI --->|               |
		|  User-   |                                | Authorization |
		|  Agent  -|----(B)-- User authenticates -->|     Server    |
		|          |                                |               |
		|          |<---(C)--- Redirection URI ----<|               |
		|          |          with Access Token     +---------------+
		|          |            in Fragment
		|          |                                +---------------+
		|          |----(D)--- Redirection URI ---->|   Web-Hosted  |
		|          |          without Fragment      |     Client    |
		|          |                                |    Resource   |
		|     (F)  |<---(E)------- Script ---------<|               |
		|          |                                +---------------+
		+-|--------+
		  |    |
		 (A)  (G) Access Token
		  |    |
		  ^    v
		+---------+
		|         |
		|  Client |
		|         |
		+---------+			   			  	
		Client lives inside browser (user agent)						
								

oAuth2 Implicit Flow

-2-

GET /authorize?
client_id=client
&scope=user.read
&reponse_type=token
&state=1234
&redirect_uri=
https://app/callback

oAuth2 Implicit Flow

-3-

Authentication is handed over to authentication server

oAuth2 Implicit Flow

-4-

303 redirect https://app/callback?
Fragment: #
access_token=AT
expires_in=3600
token_type=Bearer
&state=1234

OpenID Connect Implicit Flow

(for comparison)(spec)

-2-

GET /authorize?
client_id=client
&scope=openid
&reponse_type=id_token
&state=1234
&nonce=a_nonce
&redirect_uri=
https://app/callback

OpenID Connect Implicit Flow

-3-

Authentication is handed over to authentication server

OpenID Connect Implicit Flow

-4-

303 redirect https://app/callback?
Fragment: #
id_token=IDT
expires_in=3600
token_type=Bearer
&state=1234
&nonce=a_nonce

Preparing the environment

  • Navigate to the ./ex-7 directory
  • Install dependencies $ npm install

Explore the code

  • We use an example from microsoft, calling the graph api from javascript
  • The example uses MSAL.JS (v1). MSAL.JS may not support all modes for oAuth2 or OICD
  • Our back-end serves the static web page
    (and responds to redirects)(The hybrid)
    • server.js serves the static web page
  • The application lives in the browser
    • JavaScriptSPA/index.html

Config, Run and Explore

  • Update configuration in javaScriptSPA/index.html:msalConfig (clientid, authority)
  • Configure AD app object (Azure AD)
    • Redirect URI: http://localhost:3000
    • Authentication:Advances Setting:Implicit grant - allow access token and ID tokens
  • Configure environment back-end variables (PORT)
  • Run web application $ npm start
  • Explore SPA Client (Browser, Developer Mode)
    • Network flow to graph api - headers
    • Cookies
    • Local storage

Security considerations

  • It's a public client!
  • Implicit flow is less secure than code grant
  • The redirect GET REQUEST exposes the AccessToken/Id_Token
  • Information - like tokens are available to "everyone" using the browser
  • Good practice: Follow advice in OWASP Top 10 for Web application security (link)
  • Good practice: Always use HTTPS
  • Good practice: Use Content Security Policy
  • Good practice: Go with auth code grant flow if you can :)
  • Good advice: Use MSAL v2. ADAL (v1) will be deprecated June 30th 2022

Exercise 8

SPA - PKCE

Code flow for public clients using PKCE
Lower the risk of stolen the one time code

Outline

  • What is a PKCE?
  • The code flow with PKCE
  • Prepare environment (EX-8)
  • Explore code
  • Config, Run and Explore
  • Security considerations

What is PCKE(Pixie)?

  • Proof Key for Code Exchange
    - RFC 7636 - PKCE at oauth.net
  • "Replacing impclicit flow for public clients"
  • Extension to Authorization code flow
  • Using generated secret to avoid stealing of the one time authorization code

Elements of PCKE

For each request to get a token:

  • Generate secret known as code verifier
  • Code verifier is random generated secret. (A-Z, a-z, 0-9, and the punctuation characters -._~ (hyphen, period, underscore, and tilde), between 43 and 128 characters long.)
  • Generate a code challenge, SHA256 of code verifier - url encoded
  • code_challenge_method to specific method of verifier - plain or s256

Authorization Code Grant with PKCE

-1-

Client via user agent - initiates

Authorization Code Grant with PKCE

-2-

GET /authorize?
client_id=client
&scope=(optional)
&reponse_type=code
&state=1234
&redirect_uri= https://app/callback &code_challenge=(SHA of PKCE secret)
&code_challenge_method=S256

Authorization Code Grant with PKCE

-3-

Authentication is handed over to authentication server

Authorization Code Grant with PKCE

-4-

303 redirect https://app/callback?
code=o-t-c
&state=1234

Authorization Code Grant with PKCE

-5-

POST /token grant_type=authorization_code
&client_id=
&code_verfier=(the PKCE secret)
&code=
&redirect_uri=

Authorization Code Grant with PKCE

-6-

{
"access_token":"2YotnFZFEjr1zCsicMWpAA", "token_type":"example", "expires_in":3600, "refresh_token":"tGzv3JOkF0XG5Qx2TlKWIA", "token_type":"Bearer"
}

Preparing the environment - code

  • Navigate to the ./ex-8 directory
  • Install dependencies $ npm install

Preparing the environment - Azure AD

  • The MS identify platform support PKCE.
    MSAL.JS v2 supports PKCE.
  • For the app object (clientid) in Azure AD we need to
    • Treat the web app as a public client (app reg -> Authentication -> Advanced Settings - Default Client Type = Yes),
    • Add new platform "SPA" from "Authorization" - add redirect URI for app (http://localhost:3000/callback
    • (Alternatively: Alter manifest in the "replyUrlsWithType" section, change "type" to "Spa" for the redirect urls that will use PKCE)
  • The token request must use CORS - origin in the header

Explore the code

  • Same code as for exercise 2
  • app.js contains the web app
  • Use node module "pkce-challenge" to generate code_verifier and code_challenge
  • Alter query string for GET code request
  • Alter header and body for POST to get token
  • Add "origin" header for token request
  • Removed the "client_secret" part
  • This flow now supports refresh tokens for "public clients"

Config, Run and Explore

  • Verify the authServer object in app.js
  • Verify the client object in app.js
  • Configure environment variables
    (client_id)
  • Run web application $ npm start

Security Considerations

  • Security consideratins from RFC 7636
  • The implicit grant will most likely be deprecated in the future with oAuth 2.1
  • MSAL.js v2.0 does not support the implicit grant
  • I assume that using PKCE with code grant becomes mandatory at some point

Exercise 9

Protecting web api's


AD App, Token validation
Azure API GW - APIM

Outline

  • The scenario
  • Add AD Application Object for API
  • Explore and config the SPA code
  • Explore and config the API code
  • Run and Explore
  • Security considerations

The scenario

The Scenario

  • Two components
    • Single Page Web Application (from prev. exercise)
    • API which echoes time
  • New button in SPA to "Echo" api
  • SPA sends request to API with access token as a bearer token
  • API validates token and reponds with time if everything is ok

Adding Azure AD application object for API

  • Follow procedure in earlier exercise to register API
  • Activate "Application developer role" in "Privileged Identiy Management"
  • Name: (inital)-(aa-echo-api) or something else
  • Type: Single tenant
  • Select "Expose an API" (app config)
    • Add scope (accept suggested App ID URI)
    • Scope name: Echo.Read
    • Who can consent: Admins and Users (Add relevant text to descriptions)
    • State: Enabled
    • Remove "default" API permissions from API object (user.read)

Explore and config the SPA code

  • Navigate to the ./ex-9/spa directory
  • Install dependencies $ npm install
  • Update config in "JavaScriptSPA/index.html
  • Verify env. variables (PORT) and Azure AD App Config (redirect URI)
    • msalConfig: clientId, authority(tenant id) (for SPA AD App)
    • getEcho():requestEchoObj:scope (api://..../Echo.Read)
    • getEcho(): Url to API (http://localhost:3100)
  • The getEcho function do
    • Request an access token to access the Echo API
    • Call Echo with access token and then displays response
  • Verify the config of the AD application object. It was most likely messed up in the previous exercise

Explore and config the API code

  • In a separate terminal - Navigate to the ./ex-9/api directory
  • Install dependencies $ npm install
  • Update config in "bin/www (the port if needed)
  • Update config in "routes/index.js
    • validateOptions: audience (the api app URI)
    • validateOptions: issuer (the tenant id)
  • Update config in "app.js" (corsOptions, will only accept requests from localhost. Must be changed if the SPA is moved)
  • Code: "routes/index.js"
    • Gets the api request, using library to validate token
    • "validateOptions" defines what will be validated
    • Uses "well known endpoints" of API object to find keys++
  • Code: "./app.js"
    • The API middleware layer (Express)
    • Define CORS headers using a library

Run and explore scenario

  • Use two terminal sessions - SPA, API
  • Navigate to the ./ex-9/api and do $ npm start
  • Navigate to the ./ex-9/spa and do $ npm start
  • Explore the new "Echo" functionallity
  • Alter CORS headers and observe effect (in SPA - Dev mode
  • Alter token validation options in API and observe effect
  • Alter scope for Api in SPA and observe effect

Alternative solutions for chaining api


  • The On-Behalf-Of flow in the MS Identity Platform
  • Will be covered in the next exercise

Security considerations

  • Use libraries to do token validation
  • "No trust" - "Verify everything"
  • Good practice: Consider placing your API behind and api gateway (such as APIM)
  • Good practice: Consult the OWASP API Security Project)

Exercise 10

Protecting web api's, chaining api's

The On-Behalf-Of flow

Outline

  • The scenario
  • The On-Behalf-Of Flow
  • The Application Objects in AzureAD
  • The SPA Client (functionally, config, code)
  • The Quote API (functionally, config, code)
  • The Echo API (functionally, config, code)
  • Run and Explore
  • Security considerations

The scenario

An Api making requests on behalf of user/machine

The Scenario

An Api making requests on behalf of user/machine
  1. The Client requests an access token for the Echo Api
  2. The Client get an accesstoken for the Echo API - user consent
  3. The Client uses access token and requests an Echo
  4. The Echo Api validates the request and the access token
  5. The Echo Api requests an access token for the Quote Api (client permission)
  6. The Echo Api get a access token for the Quote Api
  7. The Echo API requests a Quote from the Quote Api
  8. The Quote Api validates the request and the access token
  9. The Quote Api returnes a cool quote
  10. The Echo Api returns a Echo w/Quote to the Client

The On-Behalf-Of (OBO) Flow

The On-Behalf-Of (OBO) Flow

The middle-tier access token request (5)
  • Request endpoint_
    https://login.microsoftonline.com//oauth2/v2.0/token
  • Request parameters
  • grant_type urn:ietf:params:oauth:grant-type:jwt-bearer
    client_id Id of the client making the request (B)
    client_secret The client (B) secret
    assertion The access token that the client (B) got from client A in step 3. Audience in claim must be client_id of client B
    scope The scope that is requested (The scope in client C)
    requested_token_use on_behalf_of

The On-Behalf-Of (OBO) Flow

The middle-tier access token request response (6)
  • Parameters in response
  • token_type Bearer
    scope The requested scope (exposed by client C)
    expires_in Number of seconds until the access token expire
    access_token The actual access token that will be used by client B when requesting from client C (step 7)

The Application Objects in AzureAD

All objects that we want to protect must be registered in Azure AD
  • SPA (Client A). Must have a client_id and client_secret (depending on which flows that are used). No changes compared to previous exercises
  • The Echo Api (Client B). Must have a client_id and a client_secret. Must expose scope for api - Echo.Read. Compared to previous exercises - we need a client_secret to be able to request a token on-behalf-of
  • The Quote Api (Client C). Must have a client_id. Must expose scope for api - GetQuote. Compared to previous exercises - this is a new registration

Preparing for the exercise

  • Code lives in ./ex-10
  • 3 projects
    • Client A - SPA (./ex-10/spa)
    • Client B - Echo Api (./ex-10/echoapi)
    • Client C - Quote Api (./ex-10/quoteapi)
  • Remember: Each project must be executed in a separate terminal window on your computer

The SPA Client

  • No code changes from previous examples (ex-9)
  • Update in "JavaSciptSPA/index.html (Link to ex-9)
  • In a separate terminal window, from ./ex-10/spa
    • Set environment variable PORT=3000
    • Do a npm install
    • Start SPA client (A) by doing npm start

The Quote API

  • New functionalliy - based on Echo api from ex-9
  • Examine code in ./ex-10/quoteapi
  • Create new App Registration for Quote Api in Azure AD
    • Expose api/scope: GetQuote
    • Authorise client application (the EchoAPI (B) to access the API)(from Expose Api section)
    • This is an example for application/machine trust - no user consent involved!
  • Update config in app (./routes/quote.js)
    • validateOptions: audience (clientID of Quote API)
    • jwt.verify(...)
      • decoded.appid = clientID of Echo Api
  • In a separate terminal window, from ./ex-10/quoteapi
    • Set environment variable PORT=3200
    • Do a npm install
    • Start Quote Api (C) by doing npm start

The Echo API

  • New functionalliy - request quote and return a part of echo request
  • Examin code for changes (./routes/index.js, ./src/quotes.js)
  • Verify config according to previous example (validate options) (ex-9)
  • Update the scope in the request form in quotes.js to reflect to Quotes scope (api://...../GetQuote)
  • Update the decoded.appid= in quotes.js to validate that the request is coming from the echoApo (appid)
  • Verify the url for the Quote Api in getQuote in quotes.js
  • In a separate terminal window, from ./ex-10/echoapi
    • Set environment variable PORT=3100, CLIENT_ID , CLIENT_SECRET
    • Do a npm install
    • Start Echo api (B) by doing npm start

Run & Explore

  • You now have 3 applications running in 3 terminal windows
  • Login to the SPA, trigger the Echo functionality and observe cool quotes, logging etc
  • Explore code, make changes and observe effect

Security consideratons

  • Things are getting complex - which always gives us security issues
    • Creds and config needs to be managed properly
    • Borders between staging environments needs to be clear (dev, test, prod)
    • Application architecture should be done carefully
  • Use frameworks as much as possible to handle the flows! We only do it the hard way in this exercise to be able understand
  • Establish good practise around debugging/tracing to understand network flow (Burp, Fiddler)
    • For NodeJS i recommend the Global Agent module to enable debugging using a network proxy

Exercise 11

Deploying to the Cloud

Radix for the win

The code

  • Fork from code in ex-4
  • Important changes going from local to the cloud
    • The deployment environment becomes dynamic. Potential specific to the cloud provider technology.
    • We use Docker to be a bit more "multi cloud" ready
    • Important URLs, like redirect_url, becomes dynamic. Added some logic to handle this for Radix
      (in ./src/app.js , ./src/authutils.js)
    • Still keeping secrets outside code. Storing the CLIENT_SECRET as a secret in Radix

Tasks

  • Fork the project at https://github.com/larskaare/sMailandStuff
    to your own user on github.com
  • Use the instructions in the README.md to configure and run the application locally (NodeJs and Docker)
  • Deploy to the cloud using Radix. A good place to start would be The Radix Getting Started

Traps ...

  • The app name in radixconfig
  • Update redirect URL in app registration
  • Update CLIENTID in radixconfig

Security Resources

Links to relevant security resources

Going deeper into the A&A topic ...

Clean-Up

  • Clean-up in Azure AD App Registration
  • Clean-up in Radix - remove app after usage

Thank You!

  • Join #appsec on Slack
  • Continue discussion on A&A and other application security related topics