Upstream Service - Authentication

Overview

Upstream service allows user to obtain an accessToken that is used for intra-service communication over HTTP and WebSocket connections in Platform infrastructure.

Obtaining a Token

Client needs to obtain access token before calling services. Token is generated as a part of successful login.

Before doing the login, client must select identity provider as an authority that handles the login / verifies user credentials. Potentially, there are many identity providers, so client must fetch list of available providers, "select" one of them, do the login against a chosen provider in the provider-specific way.

This overall process is driven by hypermedia. Authentication is described by media type based on Hypertext Application Language.

See sections below on how to get to the entry point, how to retrieve identity providers and do specific login procedures.

Entry Point Resource

This resource is available under $UPSTREAM_URL/auth URL. This is the only authentication-related URL that client must be aware of and is free to bind to.

Authentication entry point resource is a gateway to authentication functionality holding links to related resources:

application/hal+json"
{
  "_links": {
    "curies": [
      {
        "name": "auth",
        "href": "http://~/auth/def/rels/{rel}",
        "templated": true
      }
    ],
    "self": {
      "href": "http://~/auth"
    },
    "auth:identity-providers": [
      {
        "href": "http://~/auth/identity-providers"
      }
    ],
    "auth:logout": [
      {
        "name": "reactive",
        "href": "http://~/auth/logout/reactive"
      },
      {
         "name": "reactive-tpl",
         "href": "http://~/auth/logout/reactive{?return}",
         "templated": true
      }
    ],
    "auth:oauth2-token": [
       {
        "name": "refresh"
        "href": "http://~/auth/oauth2/token"
       }
    ]
    "auth:sso-login": [
      {
        "name": "start-auto"
        "href": "http://~/auth/sso/login/start/auto"
      },
      {
        "name": "start-auto-tpl"
        "href": "http://~/auth/sso/login/start/auto{?IdpAdapterId}",
        "templated": true
      },
      {
        "name": "SAML2"
        "href": "http://~/auth/sso/login/saml2"
      }
    ],
    "auth:token": [
      {
        "name": "current"
        "href": "http://~/auth/tokens/current"
      }
    ]
  }
}

Supported media type of the representation is application/hal+json".

Note presence of the link to identity providers resource via auth:identity-providers relation. If this link is available then client may fetch list of identity providers which can be used to do the login.

NOTE: Client MUST NOT have any prior knowledge about URLs in the links mentioned above as well as rely on its presence all the time. All the client MUST understand is that presence of a link with relation auth:identity-providers enables discovery of available identity providers which may be then found on the supplied URL. Link is optional and its absence means that identity providers resource is not available for some reason. Same rule applies for any other link described in this document.

Identity Providers

This resource is represented by aforementioned auth:identity-providers link relation carrying information about available identity providers:

application/hal+json"
{
  "_links": {
    "curies": [
      {
        "name": "auth",
        "href": "http://~/auth/def/rels/{rel}",
        "templated": true
      },
      {
        "name": "auth-oauth",
        "href": "http://~/auth/identity-providers/kind/oauth/def/rels/{rel}",
        "templated": true
      },
      {
        "name": "auth-ping-federate",
        "href": "http://~/auth/identity-providers/kind/ping-federate/def/rels/{rel}",
        "templated": true
      }
    ],
    "self": {
      "href": "http://~/auth/identity-providers"
    }
  },
  "_embedded": {
    "auth:identity-provider": [
      {
        "kind": "oauth",
        "_links": {
          "auth-oauth:ropc-myavid": [
            {
              "href": "https://~/auth/sso/login/oauth2/ropc/myavid"
            }
          ]
        }
      },
      {
        "kind": "ping-federate",
        "_links": {
          "auth-ping-federate:idp-sso": [
            {
              "href": "https://~/idp/startSSO.ping{?PartnerSpId,TargetResource,InErrorResource,Binding,ACSIdx,IdpAdapterId,RequestedFormat}",
              "templated": true
            }
          ]
        }
      }
      <...>
    ]
  }
}

Supported media type of the representation is application/hal+json".

Identity providers are described by embedded resources under auth:identity-provider relation. Each subresource has a kind that is used to distinguish between different identity provider kinds.

Identity providers are an actual authorities that handle the login. Authentication can be done according to specific flow of the system or via OAuth2 authentication standard. Identity providers can be added or removed via configuration.

Obtaining a Token. Resource Owner Password Credentials Grant

You can obtain a token by sending a HTTP POST request to the oauth2 identity provider endpoints with content-type of application/x-www-form-urlencoded and payload described in RFC. So, according to RFC, the payload MUST contain fields password=my_password, username=my_username and grant_type="password". Also, the request MUST have Authorization header. The Authorization header MUST contain Base 64 encoded payload < client_id:client_secret >. To make a successful login client should previously perform createComponent operation of IAM service and register component with alias=client_id and hashedSecret=sha512Hex of (client_secret + salt). More details about createComponent operation can be found in IAM documentation.

NOTE: By default in the successful response to login request, a user will get access_token and the refresh_token. The last one allows a client to use a login API more conveniently because bypassing refresh_token from first successful login will allow getting a new access_token without bypassing user credentials. Getting an access token in the response to login request is configurable. This option is enabled by default and can be disabled by passing no_refresh_token=true parameter in the login form.

The header and payload of HTTP POST request to the oauth2 identity provider endpoint will be passed to IAM service as-is. IAM is responsible for all data validation.

Example

Request → ← Response
POST /auth/sso/login/oauth2/ropc/myavid HTTP/1.1
Content-Type: application/x-www-form-urlencoded
... 
username=< username > 
password=< password > 
grant_type=password
...
Authorization: Basic < client_id:client_secret >
HTTP/1.1 200 OK
Content-Type: application/json
...
{
	"access_token": "YWU0NTIyYjgtNzFiNC00MzczLTkxMGItN2I0Yjg2NjZmODg2",
	"expires_in": 86400,
	"token_type": "bearer",
	"refresh_token": "05a90614-3bf2-43b9-ae9b-d72442d81e92",
	"scope": "avid.collaboration/* avid.iam/findPrincipal"
}

Obtaining a Token via refresh token. Resource Owner Password Credentials Grant

You can obtain a token by sending a HTTP POST request to the oauth2 identity provider endpoints with content-type of application/x-www-form-urlencoded and payload described in RFC. So, according to RFC, the payload MUST contain fields grant_type="refresh_token" and refresh_token=my_refresh_token. Also, the request MUST have Authorization header. The Authorization header MUST contain Base 64 encoded payload < client_id:client_secret >. To make a successful login client should previously perform createComponent operation of IAM service and register component with alias=client_id and hashedSecret=sha512Hex of (client_secret + salt). More details about createComponent operation can be found in IAM documentation.

The refresh token that is required in request payload can be obtained from the successful response to the login request.

Example

Request → ← Response
POST /auth/sso/login/oauth2/ropc/myavid HTTP/1.1
Content-Type: application/x-www-form-urlencoded
... 
grant_type=refresh_token
refresh_token=< my_refresh_token > 
...
Authorization: Basic < client_id:client_secret >
HTTP/1.1 200 OK
Content-Type: application/json
...
{
	"access_token": "MjM2MTJkODMtNTNmNS00YWQzLTk5NTAtNDdjMjM0YjlhM2Rj",
	"expires_in": 86400,
	"token_type": "bearer",
	"scope": "*/*"
}

Obtaining a Token. Client Credentials Grant

You can obtain a token by sending a HTTP POST request to the oauth2 identity provider endpoints with content-type of application/x-www-form-urlencoded and payload described in RFC. So, according to RFC, the payload MUST contain field grant_type="client_credentials" and also there MUST be field username=my_username. Also, the request MUST have Authorization header. The Authorization header MUST contain Base 64 encoded payload < client_id:client_secret >. To make a successful login client should previously perform createComponent operation of IAM service and register component with alias=client_id and hashedSecret=sha512Hex of (client_secret + salt). More details about createComponent operation can be found in IAM documentation.

NOTE: Refresh token is not returned in this flow.

The header and payload of HTTP POST request to the oauth2 identity provider endpoint will be passed to IAM service as-is. IAM is responsible for all data validation.

Example

Request → ← Response
POST auth/sso/login/oauth2/client-credentials/ums HTTP/1.1
Content-Type: application/x-www-form-urlencoded
... 
username=< username > 
grant_type=client_credentials
...
Authorization: Basic < client_id:client_secret >
HTTP/1.1 200 OK
Content-Type: application/json
...
{
	"access_token": "OTEyN2UyNTctMWFlMS00MzAyLWE5ZjUtYzVjMWRiOTYxMjRh",
	"expires_in": 86400,
	"token_type": "bearer",
	"scope": "*/*"
}

Client errors during ROPC an CC workflows

Upstream can emit following errors during ROPC an CC workflows:

  1. 415 Unsupported Media Type
1
2
3
4
5
6
7
8
9
10
{
"code": "avid.upstream/MALFORMED_REQUEST_ENTITY_CONTENT_TYPE",
"params": {
"contentType": "application/x-www-form-urlencoded"
},
"message": "Allowed content-type is application/x-www-form-urlencoded",
"incident": "e0f89c40-c7ca-11e7-9e0f-5254005e99a2",
"exchange": "e0f6c781-c7ca-11e7-9e0f-5254005e99a2",
"status": 415
}
  1. 404 Not Found
1
2
3
4
5
6
7
8
{
"code": "avid.upstream/NOT_FOUND",
"params": {},
"message": "Not Found",
"incident": "b29d6f00-c7cb-11e7-9e0f-5254005e99a2",
"exchange": "b29d20e1-c7cb-11e7-9e0f-5254005e99a2",
"status": 404
}
  1. 405 Method Not Allowed
1
2
3
4
5
6
7
8
{
"code": "avid.upstream/METHOD_NOT_ALLOWED",
"params": {},
"message": "Method not allowed",
"incident": "312fe381-c7cb-11e7-9e0f-5254005e99a2",
"exchange": "313031a0-c7cb-11e7-9e0f-5254005e99a2",
"status": 405
}

Using PingFederate as Identity Provider

Client interested in the login via PingFederate SHOULD find auth:identity-provider embedded resource of kind ping-federate. Hypertext reference identified within the auth-ping-federate:idp-sso link points to the PingFederate's resource for idP-initiated SSO, i.e. /idp/startSSO.ping resource. This reference is templated describing allowed query parameters.

In a typical case, client just redirects the user to that URL giving PartnerSpId, ACSIdx, IdpAdapterId and TargetResource. All of these parameters are usually pre-determined by the configuration but can also be changed by the client on demand:

  • PartnerSpId identifies the federation ID of the Service Provider to whom the SAML response containing an assertion should be issued.
  • ACSIdx specifies the index number of partner’s Assertion Consumer Service URL.
  • IdpAdapterId allows the client to call out specific adapter to use for authentication (in a configuration with multiple IdP adapters).
  • TargetResource is an indicator for a desired resource at the SP during IDP-initiated SSO.

For example, issuing the following URL:

https://ssotst.avid.com/idp/startSSO.ping?PartnerSpId=everywhere.avid.com&TargetResource=http://myapp/logged-in

will initiate the login procedure against PingFederate using everywhere.avid.com as federation ID of the Service Provider. Following things will happen:

  • Showing login screen to the user (if the user is not logged in yet). If login is successful then:
    • POSTing credentials to the Upstream. If handling is successful then:
      • avidAccessToken session cookie is created and set on the Upstream's domain - further requests to the Upstream will be authenticated unless token times out.
      • Client gets redirected to the target resource (http://myapp/logged-in).

This PingFederate server that can be used for development purposes:

https://ssotst.avid.com/idp/startSSO.ping?PartnerSpId=everywhere.avid.com&ACSIdx=1

By default, it will redirect to the Upstream residing on http://localhost:3001. Respective Upstream configuration:

/etc/sysconfig/avid-upstream
UPSTREAM_AUTH_PING_FEDERATE_HOST=ssotst.avid.com
UPSTREAM_AUTH_PING_FEDERATE_PARTNER_SP_ID=everywhere.avid.com
UPSTREAM_AUTH_PING_FEDERATE_ACS_IDX=1

Configuring Certificate for SAML Response Signature Validation

Upstream receives SAML response from PingFederate on successful user login. This response carries verification from identity provider that the user is allowed to access particular resource alongside with some user information. Upstream needs to validate signature of this response against a certificate to prove that it is coming from the trusted party.

UPSTREAM_AUTH_PING_FEDERATE_CERTIFICATE variable in /etc/sysconfig/avid-upstream configuration file is used to setup location of the PingFederate certificate. Currently, this property is commented and is pointing to PingFederate's test certificate, which is shipped with Upstream RPM for development purposes:

/etc/sysconfig/avid-upstream
#UPSTREAM_AUTH_PING_FEDERATE_CERTIFICATE=/opt/avid/etc/avid-upstream/avid-pf-tst.crt

Uncommenting it will enable signature verification against the test certificate which is valid for PingFederate environment setup on ssotst.avid.com.

Passing and Verifying Access Token

Upstream supports token-based authentication check using one of the following methods (declared in the order of the Upstream's selection preference):

  • Authorization HTTP response header with Bearer authentication scheme (recommended way).
  • _avidAccessToken query parameter.
  • avidAccessToken cookie.

Given that xyz is a valid token all requests below are treat as coming from authenticated party:

Authorization Header (recommended)
GET /apis/service/resource HTTP/1.1
<...>
Authorization: Bearer xyz
<...>
Query Parameter
GET /apis/service/resource?_avidAccessToken=xyz HTTP/1.1
<...>
Cookie
GET /apis/service/resource HTTP/1.1
<...>
Cookie: avidAccessToken=xyz
<...>

Obtaining Current Token

It is possible to retrieve current access token and IAM token associated with the current token via auth:token named current which may be found in the entry point resource:

{
    "_links": {
        "curies": {
            "name": "auth",
            "href": "http://~/auth/def/rels/{rel}",
            "templated": true
        }
    },
    <...>,
    "auth:token": [
        {
            "name": "current"
            "href": "http://~/auth/tokens/current"
        }
    ],
    <...>
}

Sample response:

{
  "_links": {
    "curies": [
      {
        "name": "auth",
        "href": "http://~/auth/def/rels/{rel}",
        "templated": true
      },
      {
        "name": "auth-token",
        "href": "http://~/auth/tokens/rels/{rel}",
        "template": true
      },
      "self": {
        "href": "http://~/auth/tokens/current"
      },
      "auth-token:extend": [
        {
            "href": "http://~/auth/tokens/current/extension"
        },
      "auth-token:removal": [
        {
            "href": "http://~/auth/tokens/current"
        }
    ]
  },
  "accessToken": "OWQzZWQyOGEtYWQ1YS00ZjU2LWJkMWUtMGM2NTEwMmUzMjkx",
  "iamToken": {
	"clientMachineId": null,
	"identityId": "410c8aa5-465c-42b8-a75b-56d40472da9f",
	"identityMasterRegion": "us-east-1",
	"contextId": "410c8aa5-465c-42b8-a75b-56d40472da9f",
	"contextMasterRegion": "us-east-1",
	"expiresAt": "2018-05-24T15:16:00.694Z",
	"componentId": "f9ab9f3f-175d-4006-b445-5d169a4c1f50",
	"componentScope": "*/*",
	"createdAt": "2018-05-23T15:16:00.701Z",
	"updatedAt": "2018-05-23T15:16:00.701Z",
	"masterRegion": "us-east-1",
	"id": "9d3ed28a-ad5a-4f56-bd1e-0c65102e3291"
  }
}

Supported media type of the representation: application/hal+json"

NOTE: Client MUST NOT have any prior knowledge about URL in the links mentioned above as well as rely on its presence all the time. All the client MUST understand is that presence of a link enables discovery of the "current" token. Link is optional and its absence means that respective resource is not available.

It is possible to log out via auth-token:removal link by sending DELETE request to it. The request will look like:

DELETE /auth/tokens/current
...
Cookie: avidAccessToken=...

If operation is successful then 204 No Content status will be returned in response.

Extending current token

It is possible to extend token expiration time, for this you should send POST request to the link under the auth-token:extend rel. So, the request will look like:

POST /auth/tokens/current/extension
...
Cookie: avidAccessToken=...

The request body MUST be empty. The token will be extended as defined by the semantics of IAMs mergeToken operation when no expiresAt and expiresIn is specified.

If extending token expiration is successful, then you will receive 200 OK status with actual content of the token. Client MUST refresh / replace the token on it's side since access token MAY be rotated by the server.