SSO Integration | Aayu Technologies
Link Search Menu Expand Document

AS2 Gateway SSO Integration

SSO on AS2 Gateway (AS2G) is implemented for OIDC (OpenID connect), based on shared claims.

  • OIDC platform (OIP) has each user assigned to a set of groups
  • AS2G has same set of groups pre-defined, each with assigned AS2G-level roles/permissions
  • Once a SSO logged-in user lands in AS2G, they get mapped into a virtual user on AS2G side, assigned with relevant set of groups (and corresponding roles/permissions)

Group-based permission mapping during SSO

OIP must expose group names as a claim in the issued credential/token. Field name of the claim is expected to be “groups”; if different, the value can be configured on AS2G side.

As a fallback, mapping users by username (via a claim “email” on the token) is also available; in this case, instead of groups, administrators have to create actual user entries (matching the SSO users) on AS2G side, and assign them to groups with appropriate role/permission levels.

Limitations

  • Only JSON web tokens (JWT) are supported as OIP credentials; opaque tokens cannot be decoded or verified by AS2G for necessary authorization steps.
  • In case of multi-tenant AS2G set-ups (uncommon in dedicated deployments), group names must be unique across tenants. If an OIP-issued token specifies groups A,B,C but AS2G detects that group B is present in both tenants X and Y, it will deny authorization with a HTTP 401 error and a corresponding log line in backend logs.

Configuration

Setting following Spring properties (usually as environment variables) on backend, enables SSO for a platform “Acme-SSO”:

# provider's base OIDC URL; exposed to frontend
# e.g. if configuration URL is https://acme.sso/baz/.well-known/openid-configuration, base URL is https://acme.sso/baz
openid.provider.Acme-SSO.baseUrl=

# OIDC app client ID; exposed to frontend
openid.provider.Acme-SSO.clientId=

# OIDC app client secret; can be omitted if PKCE (https://oauth.net/2/pkce/) is in-use instead
openid.provider.Acme-SSO.clientSecret=

# (optional) automatically expire any JWKS (keys) obtained from OIDC server's JWKS endpoint, by this schedule
# format: <second> <minute> <hour> <day-of-month> <month> <day-of-week>
openid.provider.Acme-SSO.jwksExpirationCron=

# (optional) any additional/static JWKs (not present in JWKS endpoint response) can be configured here, as <key-id> and <key-value> pairs
openid.provider.Acme-SSO.additionalKeys.<key-id>=<key-value>

# (optional) name (JSON key) of the token to be extracted from the auth-code exchange response
# (which usually contains access, ID and refresh tokens); default "id_token" 
openid.provider.Acme-SSO.tokenName=

# (optional) claim name (JSON key) that the provider uses for denoting username, inside JWT body, if different from "email"; exposed to frontend
openid.provider.Acme-SSO.userClaimName=

# (optional) claim name (JSON key) that the provider uses for denoting groups, inside JWT body, if different from "groups"; exposed to frontend
openid.provider.Acme-SSO.groupsClaimName=


# for each provider, these additional entries must be configured to expose corresponding backend properties for frontend OIDC auth flow
# a 'Log-in with <provider name>' button would appear in UI, for each such configured provider
webapp.config.auth.provider.Acme-SSO.clientId=${openid.provider.Acme-SSO.clientId}
webapp.config.auth.provider.Acme-SSO.baseUrl=${openid.provider.Acme-SSO.baseUrl}

# (next entries are not required if not overridden:)
openid.provider.Acme-SSO.tokenName=${openid.provider.Acme-SSO.tokenName}
webapp.config.auth.provider.Acme-SSO.userClaimName=${openid.provider.Acme-SSO.userClaimName}
webapp.config.auth.provider.Acme-SSO.groupsClaimName=${openid.provider.Acme-SSO.groupsClaimName}

# override the scopes string on the authorization request, e.g. "openid groups" to request group information to be returned; default "openid"  
webapp.config.auth.provider.Acme-SSO.scopes=

# set to true if a client-secret is in use for auth-code exchange; usually not required if PKCE is supported by the OIDC app client
webapp.config.auth.provider.Acme-SSO.serverSide=true


# internal; app-level redirect URI for implicit auth
openid.redirect_uri=${host.url}/openid-callback


# required for loading OpenID configuration into browser environment
# last entry must be the root URL of OIDC endpoint (protocol://host:port i.e. NOT baseUrl)
security.headers.csp=default-src 'self' 'unsafe-inline' data: https://fonts.googleapis.com https://www.gstatic.com https://fonts.gstatic.com https://acme.sso

With this change, a “Log in with Acme-SSO” button will automatically appear on the log-in page.

Multiple SSO providers can be configured in this manner.

By default, direct password-based log-in (via DB-backed users) is also enabled, even with SSO configured. (Initial creation of groups would have to be performed through such a direct log-in.) When configuration steps are complete, you can turn off direct log-in by setting the following properties on backend:

auth.direct=false
webapp.config.auth.direct=false

Troubleshooting

SSO authorization may fail due to various reasons. Due to security concerns, these reasons are deliberately excluded from the user-facing errors returned for front-end display/consumption. By default the backend logs also contain limited information regarding such auth errors.

For troubleshooting, following environment variable can be set on backend to increase log levels of SSO workflow:

OPENID_LOG_LEVEL=TRACE

This will log each request and response exchanged with the configured OIDC endpoint, as follows:

# request to provider, e.g.
# Acme-SSO < https://acme.sso/baz/openid/token grant_type=authorization_code&response_type=token&...
[provider name] < [request URL] [request content]

# response from provider, e.g.
# Acme-SSO > {"access_token":"...",...}
[provider name] > [response data]

Additional actions such as auth rejections, token decoding, JWK (key) rotation, etc. will also be logged.