Enterprise Authentication

These are some notes on how authentication can be done in an enterprise. This all falls under Identity and Access Management.

Some ways of doing identity verification:

  • Direct Authentication – app maintains user identity information
    • Username / Password
    • Smart cards
    • Biometrics
  • Federated
    • Third-party authentication – SAML/OAuth

Some ways of using identity:

  • AuthN
  • AuthZ
  • Identity Delgation

 

SAML vs OAuth

There are two major claims/token-based protocol families.

SAML – (Security Assertion Markup Language) used widely in enterprise for SSO. Used often for webapps. It is more heavier than OAuth as it is based on XML where as OAuth is JSON based. Somewhat expensive to validate but has many options.

The user initiates a request to a service provider, which will redirect them to the identity provider (idP), in which it will pickup a SAML token and go back to the service provider (SP).

Below is an example SAML token with a signed certificate.

 <samlp:Response xmlns:samlp="urn:oasis:names:tc:SAML:2.0:protocol" xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion" ID="_8e8dc5f69a98cc4c1ff3427e5ce34606fd672f91e6" Version="2.0" IssueInstant="2014-07-17T01:01:48Z" Destination="http://sp.example.com/demo1/index.php?acs" InResponseTo="ONELOGIN_4fee3b046395c4e751011e97f8900b5273d56685">
  <saml:Issuer>http://idp.example.com/metadata.php</saml:Issuer>
  <samlp:Status>
    <samlp:StatusCode Value="urn:oasis:names:tc:SAML:2.0:status:Success"/>
  </samlp:Status>
  <saml:Assertion xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xs="http://www.w3.org/2001/XMLSchema" ID="pfxcaa39c56-dd01-9937-8389-7a7e9a2eda2b" Version="2.0" IssueInstant="2014-07-17T01:01:48Z">
    <saml:Issuer>http://idp.example.com/metadata.php</saml:Issuer><ds:Signature xmlns:ds="http://www.w3.org/2000/09/xmldsig#">
  <ds:SignedInfo><ds:CanonicalizationMethod Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/>
    <ds:SignatureMethod Algorithm="http://www.w3.org/2000/09/xmldsig#rsa-sha1"/>
  <ds:Reference URI="#pfxcaa39c56-dd01-9937-8389-7a7e9a2eda2b"><ds:Transforms><ds:Transform Algorithm="http://www.w3.org/2000/09/xmldsig#enveloped-signature"/><ds:Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/></ds:Transforms><ds:DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"/><ds:DigestValue>4RvVDJyIiM5w885tuQhvr9w/epk=</ds:DigestValue></ds:Reference></ds:SignedInfo><ds:SignatureValue>x3tf6fdiH+qfAuAUSllh+0ZzkxZVHVtA+LB7qoJc/ToNSvDKQAXA3zpiYD9p/ol8qR1Ws51h2P/ITMrRoTks4suVjfAtvQHPIGhfgVk/Z5ux+pQyQ+gfnbPA1Ttfrkv15Jfflu3s3wKT2DFaCZV0qJyqX+LduD6VXAvWdgNgarU=</ds:SignatureValue>
<ds:KeyInfo><ds:X509Data><ds:X509Certificate>MIICajCCAdOgAwIBAgIBADANBgkqhkiG9w0BAQ0FADBSMQswCQYDVQQGEwJ1czETMBEGA1UECAwKQ2FsaWZvcm5pYTEVMBMGA1UECgwMT25lbG9naW4gSW5jMRcwFQYDVQQDDA5zcC5leGFtcGxlLmNvbTAeFw0xNDA3MTcxNDEyNTZaFw0xNTA3MTcxNDEyNTZaMFIxCzAJBgNVBAYTAnVzMRMwEQYDVQQIDApDYWxpZm9ybmlhMRUwEwYDVQQKDAxPbmVsb2dpbiBJbmMxFzAVBgNVBAMMDnNwLmV4YW1wbGUuY29tMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDZx+ON4IUoIWxgukTb1tOiX3bMYzYQiwWPUNMp+Fq82xoNogso2bykZG0yiJm5o8zv/sd6pGouayMgkx/2FSOdc36T0jGbCHuRSbtia0PEzNIRtmViMrt3AeoWBidRXmZsxCNLwgIV6dn2WpuE5Az0bHgpZnQxTKFek0BMKU/d8wIDAQABo1AwTjAdBgNVHQ4EFgQUGHxYqZYyX7cTxKVODVgZwSTdCnwwHwYDVR0jBBgwFoAUGHxYqZYyX7cTxKVODVgZwSTdCnwwDAYDVR0TBAUwAwEB/zANBgkqhkiG9w0BAQ0FAAOBgQByFOl+hMFICbd3DJfnp2Rgd/dqttsZG/tyhILWvErbio/DEe98mXpowhTkC04ENprOyXi7ZbUqiicF89uAGyt1oqgTUCD1VsLahqIcmrzgumNyTwLGWo17WDAa1/usDhetWAMhgzF/Cnf5ek0nK00m0YZGyc4LzgD0CROMASTWNg==</ds:X509Certificate></ds:X509Data></ds:KeyInfo></ds:Signature>
    <saml:Subject>
      <saml:NameID SPNameQualifier="http://sp.example.com/demo1/metadata.php" Format="urn:oasis:names:tc:SAML:2.0:nameid-format:transient">_ce3d2948b4cf20146dee0a0b3dd6f69b6cf86f62d7</saml:NameID>
      <saml:SubjectConfirmation Method="urn:oasis:names:tc:SAML:2.0:cm:bearer">
        <saml:SubjectConfirmationData NotOnOrAfter="2024-01-18T06:21:48Z" Recipient="http://sp.example.com/demo1/index.php?acs" InResponseTo="ONELOGIN_4fee3b046395c4e751011e97f8900b5273d56685"/>
      </saml:SubjectConfirmation>
    </saml:Subject>
    <saml:Conditions NotBefore="2014-07-17T01:01:18Z" NotOnOrAfter="2024-01-18T06:21:48Z">
      <saml:AudienceRestriction>
        <saml:Audience>http://sp.example.com/demo1/metadata.php</saml:Audience>
      </saml:AudienceRestriction>
    </saml:Conditions>
    <saml:AuthnStatement AuthnInstant="2014-07-17T01:01:48Z" SessionNotOnOrAfter="2024-07-17T09:01:48Z" SessionIndex="_be9967abd904ddcae3c0eb4189adbe3f71e327cf93">
      <saml:AuthnContext>
        <saml:AuthnContextClassRef>urn:oasis:names:tc:SAML:2.0:ac:classes:Password</saml:AuthnContextClassRef>
      </saml:AuthnContext>
    </saml:AuthnStatement>
    <saml:AttributeStatement>
      <saml:Attribute Name="uid" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:basic">
        <saml:AttributeValue xsi:type="xs:string">test</saml:AttributeValue>
      </saml:Attribute>
      <saml:Attribute Name="mail" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:basic">
        <saml:AttributeValue xsi:type="xs:string">test@example.com</saml:AttributeValue>
      </saml:Attribute>
      <saml:Attribute Name="eduPersonAffiliation" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:basic">
        <saml:AttributeValue xsi:type="xs:string">users</saml:AttributeValue>
        <saml:AttributeValue xsi:type="xs:string">examplerole1</saml:AttributeValue>
      </saml:Attribute>
    </saml:AttributeStatement>
  </saml:Assertion>
</samlp:Response>

The SAML token contains information that would only work for the specific service provider. The token cannot be used elsewhere.

 

SAML Example

The following .Net Core application using SAMLv2 authentication against an Azure Active Directory. It is using the WS-Federation library (v2.2) available for .Net Core (v2.2). Full source can be found here:

https://github.com/johnlee/tbd…

In the startup.cs class we need to configure the authentication service in the ConfigureServices() method. Below is a code excerpt I’ve added.

services.AddAuthentication(authOptions =>
{
    authOptions.DefaultScheme = CookieAuthenticationDefaults.AuthenticationScheme;
    authOptions.DefaultSignInScheme = CookieAuthenticationDefaults.AuthenticationScheme;
    authOptions.DefaultChallengeScheme = WsFederationDefaults.AuthenticationScheme;
})
.AddWsFederation(wsfedOptions =>
{
    wsfedOptions.Wtrealm = "xxx-ffff-zzzz-wwww-eeeeeeeeee";
    wsfedOptions.MetadataAddress = "https://login.microsoftonline.com/aaa-bbb-ccc-ddd-eee/federationmetadata/2007-06/federationmetadata.xml";
})
.AddCookie();

The WsFederation configuration requires a Wtrealm and MetadataAddress. The Wtrealm is the application Id generated in Azure when setting up an Active Directory application. More information on how this code works and how to setup Azure can be found below:

https://azure.microsoft.com/en-us/resources/samples/active-directory-dotnet-webapp-wsfederation/

 

OAuth – started at Facebook/Google for AuthZ and AuthN. Based on JSON, the payload is small (lightweight compared to SAML). Cheap to validate but lacks in security options. Works similar to Kerberos. Basically there are 3 steps:

  1. User/client wanting access to resource gets redirected to Authorization Server for a grant
  2. User/client receives grant from Authorization Server in form of an Access Token
  3. User/client redirects back to resource with Access Token and is able to access resource

Below is an example of what an Access Token can look like in the response of step 2 above

 HTTP/1.1 200 OK
  Content-Type: application/json;charset=UTF-8
  Cache-Control: no-store
  Pragma: no-cache
  {
  "access_token":"mF_9.B5f-4.1JqM",
  "token_type":"Bearer",
  "expires_in":3600,
  "refresh_token":"tGzv3JOkF0XG5Qx2TlKWIA"
  }

There are two versions of OAuth:

  • v1 uses string signatures, not as secure
  • v2 uses tokens over HTTPS, more secure

Today OAuth2 is the recommended path. In OAuth2 there are two different types of tokens

  • Access Token – provides the actual access to the resource. There are two types of access tokens.
    • Bearer Tokens – This token is agnostic of the actual user/client. This token just states that the resource can be accessed within the given time range with this bearer token. If an app doesn’t need user information, this type of token can work – though we can also append other user information in this token to identify the user. However in it’s basic definition, anyone who has a bearer token has access to the stated resource.
    • MAC Tokens – provides a way to have cryptographic verification of a request. This has more security than just a bearer token. It makes the client-to-resource connection unique and difficult to replicate – unlike the bearer token in which anyone who steals that token could access the resource.
  • Refresh Token – used to get a new Access token when it expires.

To get a token from an Authorization Server, users/consumers are given what is called a grant. There 4 grant types:

  • Authorization Code – most complex but most secure; requires a client backend to do an additional authorization step between the client and the authorization server.
    • User goes to client (app or webpage) and is redirected to the Authorization server
    • User is prompted to login at Authorization server
    • Authorization server redirects user back to client server with authorization code
    • Client server backend submits another request to Authorization server using authorization code, client id and client secret; Authorization server responds with the actual access token
    • Client server now has the user’s access token which it can then use to access whatever other resources
  • Implicit – similar to the Authorization Code but removes the authorization step. Instead, the user goes to the authorization server to login and is immediately issued the access token. This token is usually stored in the browser memory (or URL). So it is less secure.
  • Resource Owner Credentials / Passwords – Users enter their login information directly on the client instead of redirecting to the Authorization server and logging in there. The client will capture the user id/password and work with the Authorization server to get the access tokens.
  • Client Credentials – this is used for backend services where there is no user; therefore no user login page necessary; via API calls the backend service will interact directly with the Authorization server.

 

OAuth Example

When using OAuth, we have different tokens that can be used depending on the Identity Provider. For example, when using Google’s OAuth2 API, our application will need to register with Google to setup a trusted connection. This is done by getting a client key and secret from Google. This key will be used on our app to validate Google as the Identity Provider.

Next when a user hits our app and needs to authenticate, we would redirect them to Google’s OAuth endpoint with some information about our app and instructions on what we need back from them. Such an URL could look like so:

https://accounts.google.com/o/oauth2/v2/auth
   ?client_id=139281538940-arh29cscgqk2vic01ackiphugqe6m2lr.apps.googleusercontent.com
   &response_type=code
   &scope=openid%20email
   &redirect_uri=http%3A%2F%2F256stuff.com%2Fgray%2Fdocs%2Foauth2.0%2FcomeBack.cgi
   &state=this-should-be-some-generated-secret-token

After the user authenticates with Google, they will be redirected back to our site. Google will include some key (or code) as part of this return. The redirect URL from Google could look like:

http://256stuff.com/gray/docs/oauth2.0/comeBack.cgi
   ?state=this-should-be-some-generated-secret-token
   &code=4/Ei4UjaDc5rNnV2U8Ie8MJVFm-zIQs3ysoQ
   &authuser=0
   &prompt=consent
   &session_state=1c0e1b49853dba76fe6098d4feb1d4c..2062#

This code is what we will use to validate the token. From our app side, we do another POST back to Google with the received Code and the Client Key/Secret we have when we first setup our trusted connection. That post may go to here on Google side:

https://www.googleapis.com/oauth2/v4/token 

POST /oauth2/v4/token HTTP/1.1
Host: www.googleapis.com
Content-Type: application/x-www-form-urlencoded

code=4%2FEi4UjaDc5rNnV2U8Ie8MJVFm-zIQs3ysoQ
&client_id=139281538940-arh29cscgqk2vic01ackiphugqe6m2lr.apps.googleusercontent.com
&client_secret=nvDSpUI4R6iga0xfcvO7-V-s
&redirect_uri=http%3A%2F%2F256stuff.com%2Fgray%2Fdocs%2Foauth2.0%2FcomeBack.cgi
&grant_type=authorization_code

If Google responses with a success then our app can now trust that user who has authenticated with Google.

 

OpenID Connect

OAuth protocol was originally for AuthZ, not AuthN. OAuth could be poor for AuthN because there is no way to get user information. Facebook/Google and other implementers of OAuth worked around this by having their own additions/hacks to include user information. This led to many OAuth variants, so there were efforts to standardize it which resulted in OpenID Connect. This is a layer that sits above OAuth.

Basically OpenID appends an ID Token on top of the Access Token. The ID token is encoded as a JWT (pronounced as ‘jwot’). This is a very popular strategy for frontend use cases such as mobile app, SPA web apps, etc.

 

Kerberos

Kerberos authentication solution that is often used in enterprise and ties to Active Directory. The reason being that everything must be configured together for Kerberos to work. This include end users and all services/servers that the end users will be accessing. All these asset information in stored in a KDC (Kerberos Domain Controller) which is like a database of assets and keys to access those assets. This database is encrypted and protected.

Users in Kerberos are configured in KDC using their password (in other words KDC knows all user passwords). The assets are configured in KDC using their SPN (Service Principal Names). SPN is an identifier that can look something like “service\principal@REALM”, for example: HTTP\srvs1.example.com@EXAMPLE.COM

When a user first logs onto their machine, the machine negotiates with the KDC to get a TGT for that user. Any subsequent requests to the KDC will be using the TGT. The TGT and any other Kerberos tickets are stored in the “Kerberos Tray” on the client side so it doesnt need to fetch the tickets per each request. These tickets have a timed expiration.

The request flow goes something like shown below:

Below is an example of what can be seen in a kerbtray (using Powershell/Linux shell ‘klist’ command).

PS C:\Users\lee> klist
Current LogonId is 0:0x2a69fa7
Cached Tickets: (10)

#0>     Client: lee @ contoso.com
        Server: krbtgt/contoso.com @ contoso.com
        KerbTicket Encryption Type: AES-256-CTS-HMAC-SHA1-96
        Ticket Flags 0x40e10000 -> forwardable renewable initial pre_authent name_canonicalize
        Start Time: 1/21/2015 13:45:41 (local)
        End Time:   1/21/2015 23:45:41 (local)
        Renew Time: 1/28/2015 13:45:41 (local)
        Session Key Type: AES-256-CTS-HMAC-SHA1-96
        Cache Flags: 0x1 -> PRIMARY
        Kdc Called: KDC.contoso.com

#1>     Client: lee @ contoso.com
        Server: HTTP/eidp.contoso.com @ contoso.com
        KerbTicket Encryption Type: RSADSI RC4-HMAC(NT)
        Ticket Flags 0x40a10000 -> forwardable renewable pre_authent name_canonicalize
        Start Time: 1/21/2015 14:40:13 (local)
        End Time:   1/21/2015 23:45:41 (local)
        Renew Time: 1/28/2015 13:45:41 (local)
        Session Key Type: RSADSI RC4-HMAC(NT)
        Cache Flags: 0
        Kdc Called: KDC.contoso.com

#2>     Client: lee @ contoso.com
        Server: LDAP/adi.contoso.com/contoso.com @ contoso.com
        KerbTicket Encryption Type: AES-256-CTS-HMAC-SHA1-96
        Ticket Flags 0x40a50000 -> forwardable renewable pre_authent ok_as_delegate name_canonicalize
        Start Time: 1/21/2015 13:47:41 (local)
        End Time:   1/21/2015 23:45:41 (local)
        Renew Time: 1/28/2015 13:45:41 (local)
        Session Key Type: AES-256-CTS-HMAC-SHA1-96
        Cache Flags: 0
        Kdc Called: KDC.contoso.com

#3>     Client: lee @ contoso.com
        Server: HTTP/api.contoso.com @ contoso.com
        KerbTicket Encryption Type: RSADSI RC4-HMAC(NT)
        Ticket Flags 0x40a10000 -> forwardable renewable pre_authent name_canonicalize
        Start Time: 1/21/2015 13:47:05 (local)
        End Time:   1/21/2015 23:45:41 (local)
        Renew Time: 1/28/2015 13:45:41 (local)
        Session Key Type: RSADSI RC4-HMAC(NT)
        Cache Flags: 0
        Kdc Called: KDC.contoso.com

 

 

 

References

Windows Identity Foundation – WSFederation
https://docs.microsoft.com/en-us/dotnet/framework/security/wsfederation-authentication-module-overview

SAML Authentication using Azure Active Directory
https://azure.microsoft.com/en-us/resources/samples/active-directory-dotnet-webapp-wsfederation/

WSFederation with Azure AD
https://cmatskas.com/asp-net-core-saml-authentication-with-azure-ad/

OAuth 2.0 Bearer Tokens
https://dzone.com/articles/oauth-20-bearer-token-profile

Animation of how Kereberos works
https://www.youtube.com/watch?v=kp5d8Yv3-0c