Skip to content
Architecture > Authentication

OAuth

Introduction

OAuth is one of the multiple ways you can authenticate users to 3forge AMI. The 3forge AMI OAuth Plugin makes it easy to integrate AMI with any OAuth based identity manager. It provides a simple standard authentication mechanism and allows you to build access control into your 3forge AMI Layouts.

OAuth Quickstart

Quickstart Instructions

Prerequisites:

  1. Find out your identity provider and ensure it allows for OAuth 2.0 Authentication. You will need to know the identity provider url.
  2. Register a new Web App with your identity provider.
    1. Provide a Sign In Redirect Url, we recommend https://<your-server>:33332/oauthRedirectUrl
      1. This will be used in the oauth.redirect.url property
    2. Provide a Sign Out Redirect Url (Optional but recommended)

How to setup the OAuth Plugin

  1. Navigate to your 3forge AMI config directory, it's typically located in ami\amione\config
  2. Create a file called local.properties if one is not already present
  3. Add the properties from the Minimal Configuration below to the file local.properties
  4. Update the values of the properties to match your identity provider.
  5. Restart 3forge AMI

Minimal Configuration

Note: Please refer to Properties for a detailed understanding of each property

sso.plugin.class=com.f1.ami.web.AmiWebOAuthPluginImpl

# Provide the url to your OAuth 2.0 identity provider
oauth.server.domain=<https://oauthprovider.com>

# Provide the redirect url that you configured for the app with your identity provider
oauth.redirect.uri=<http://localhost:33332/oauthRedirectUrl>

# Provide the endpoints for authorization, token and refresh token
oauth.authorization.endpoint=/authorizeEndpoint
oauth.token.endpoint=/tokenEndpoint
oauth.refresh.token.endpoint=/refreshTokenEndpoint

# Properties related to refresh tokens, redirect uri and scope are optional, by default are set to null
oauth.refresh.redirect.uri=/refreshRedirectUri
oauth.refresh.scope=/refreshScope
oauth.refresh.client.id=/refreshClientId
oauth.refresh.client.secret=/refreshClientSecret

# Provide the client id and secret that will be used for the OAuth authentication
oauth.client.id=clientid
oauth.client.secret=secret

# Replace this with the default scope that is used for Web Based Applications in your firm
oauth.scope=openid profile email offline_access

# Replace this with unique identifier that identifies the user
oauth.username.field=email

# Recommended to replace this with an attribute that identifies the group a user belongs to
oauth.ami.isdev.field=email
oauth.ami.isdev.values=`<comma_delimited_list_of_emails>`{=html}

# Logout Page AMI will display when logged out
web.logged.out.url=/loggedout.htm

# This is enabled for development, disable this after OAuth has been setup
oauth.debug=true

Properties

Required

  • sso.plugin.class=com.f1.ami.web.AmiWebOAuthPluginImpl Specify class to use Oauth SSO
  • oauth.server.domain=https://oauthprovider.com The domain of the auth server account
  • web.logged.out.url=/loggedout.htm Set AMI logged out page
  • oauth.redirect.uri=http://localhost:33332/oauthRedirectUrl/ 3forge AMI Url for Oauth server to redirect after login
  • oauth.client.id=clientid Client ID
  • oauth.client.secret=secret Client secret
  • oauth.authorization.endpoint=/authorizeEndpoint Authorization endpoint
  • oauth.token.endpoint=/tokenEndpoint Token endpoint
  • oauth.scope=openid profile email offline_access Oauth scope
  • oauth.username.field=email User Email

Optional

  • oauth.refresh.token.endpoint=/refreshTokenEndpoint The endpoint to get the refresh token
  • oauth.refresh.redirect.uri=/refreshRedirectUri The refresh redirect uri, by default is null, can be overriden
  • oauth.refresh.scope=/refreshScope The refresh scope, by default is null,can be overriden
  • oauth.refresh.client.id=/refreshClientId The client Id after refresh, by default is the same as oauth.client.id,can be overriden
  • oauth.refresh.client.secret=/refreshClientSecret The client Sercret after refresh, by default is the same as oauth.client.secret,can be overriden
  • oauth.ami.isdev.field=email Dev User Email
  • oauth.ami.isdev.values= List of dev user emails
  • oauth.access.token.expires.in=expires_in Key that contains the time the access token expires in
  • oauth.code.challenge.method=S256 Code challenge method
  • oauth.digest.algo=SHA-256 Java hashing algorithm
  • oauth.session.check.period.seconds=60 Seconds to check refresh token expiration
  • ami.web.index.html.file=index2.htm The 3forge AMI endpoint that triggers the build auth request.
  • oauth.debug=true Enables Debugging Mode
  • oauth.validate.certs=false Disables certificate validation for SSL
  • oauth.dynamic.redirect=true Enables access to AMI via both IP address and domain url. (Requires both urls to be registered in your OAuth provider's setting)

Custom OAuth Plugin

The AMI OAuth plugin handles authorization code and access token requests that are needed for Authenticating to AMI. By extending the 3forge AMI OAuth plugin, you can create your own Ami OAuth Plugin if you have custom requirements for access control or entitlements.

There are three main components to the 3forge AMI OAuth Plugin: buildAuthRequest, processResponse, and createAmiUserSSOSession.

Main Components

The <strong>buildAuthRequest </strong>method is responsible for creating the url for the Authorization Code request.

The <strong>processResponse </strong>method is responsible for processing the response from the Authorization Code request, then building an Access Token request. Once it obtains an access token, it needs to return an AmiAuthUser.

The <strong>createAmiUserSSOSession </strong>is responsible for creating the AmiAuthUser and OAuthSSO Session. The AmiAuthUser can be used to set user session variables or restrict access to layouts. The OAuth Session is accessible in AMIScript by session.getSsoSession().

Protocol Diagram

Example Java Code

package com.company.3forge;


import java.util.Map;
import com.f1.ami.web.auth.AmiAuthUser;
import com.f1.container.ContainerTools;
import com.f1.http.HttpRequestResponse;
import com.f1.http.HttpSession;
import com.f1.suite.web.HttpRequestAction;
import com.f1.utils.PropertyController;


public class AmiWebOAuthPluginSample extends AmiWebOAuthPluginImpl {
    @Override
    public void init(ContainerTools tools, PropertyController props) {
        // This is where you can initialize any properties.
        super.init(tools, props);
        String sample = props.getRequired("oauth.sample.property");
        String sample2 = props.getOptional("oauth.sample2.property", "defaultValue");
    }
    @Override
    public String getPluginId() {
        return "SampleOAuthPlugin";
    }
    @Override
    public String buildAuthRequest(HttpRequestResponse req) throws Exception {
        HttpSession session = req.getSession(true);
        String requestUri = req.getRequestUri(); // This will be your ami.web.index.html.file
        Map<String, String> header = req.getHeader();
        Map<String, String> cookies = req.getCookies();
        Map<String, String> params = req.getParams();


        // This is how you can add a cookie to the response
        String optionalDomain = null;
        long optionalExpires = 0;
        req.putCookie("myCookie", "secretCode", optionalDomain, optionalExpires, null);


        // This is how you add a header to the response
        req.putResponseHeader("myHeader", "value");


        // This will build an Authorization Code Request
        String redirectUrlForLogin = super.buildAuthRequest(req);
        return redirectUrlForLogin;
    }
    @Override
    public String getExpectedResponsePath() {
        // This returns the login redirect url that is provided to your identity manager, it is used in the buildAuthRequest
        return super.getExpectedResponsePath();
    }
    @Override
    public AmiAuthUser processResponse(HttpRequestAction req) throws Exception {
        HttpRequestResponse authorizeResponse = req.getRequest();


        // 1| Create access token request
        Map<String, Object> accessTokenResult = doAccessTokenRequest(authorizeResponse);
        if (accessTokenResult == null)
            return null;
        AmiAuthUser user = createAmiUserSSOSession(authorizeResponse, accessTokenResult);


        // You may add your own properties to the AmiAuthUser via the auth attributes
        Map<String, Object> authAttributes = user.getAuthAttributes();


        // The below is the OAuth session which can be accessed via AMIScript through session.getSsoSession() which returns a SsoSession object
        AmiWebOAuthSsoSession oauthSession = (AmiWebOAuthSsoSession) authAttributes.get(AmiAuthUser.PROPERTY_SSO_SESSION);
        Map<String, Object> oauthSessionProperties = oauthSession.getProperties();
        return user;
    }
    @Override
    protected Map<String, Object> doAccessTokenRequest(HttpRequestResponse request) {
        // TODO Auto-generated method stub
        // If you need to change how the access token request operates
        return super.doAccessTokenRequest(request);
    }
    @Override
    protected Map<String, Object> doRefreshTokenRequest(AmiWebOAuthSsoSession ssoSession) {
        // TODO Auto-generated method stub
        // If you need to change how the refresh token request operates
        return super.doRefreshTokenRequest(ssoSession);
    }


}

Example Configuration

1
2
3
4
5
6
7
8
9
sso.plugin.class=com.company.3forge.AmiWebOAuthPluginSample

\# Include the same properties you need for the Quick Start Guide

\# ...

\# Enabling debug for development to help with diagnosing

oauth.debug=true

OAuth for Okta

The Okta plugin is a specific version of the OAuth Plugin, see below for the list of properties requrieD:

  • sso.plugin.class: The class the implements the AmiWebSSOPlugin. Use com.f1.amioktaauth.AmiOktaOauthPlugin
  • oauth.client.id: Client Id of the application registered to authenticate via OKTA.
  • oauth.client.secret: Client secret of the application registered to authenticate via OKTA.
  • oauth.redirect.uri: The uri OKTA will use to redirect the user once authentication is complete. In this case it will be the uri of amiweb (http://localhost:33332/oktaAuthFinished/). Note that this uri must match with the one configured in OKTA account.
  • oauth.server.domain: The domain of the okta account (<https://something.okta.com>)
  • oauth.scope: Space delimited scopes indicating the types of resources AMI will be requesting from the resource server. Use openid profile email
  • web.logged.out.url: url to redirect to when logged out, default is / which directs to login page. (Hint: set to /loggedout.htm for a logged out page instead, useful for OAUTH)
  • oauth.authorization.endpoint: Okta authorization endpoint. Default value /oauth2/default/v1/authorize
  • oauth.token.endpoint: Okta token endpoint. Default value /oauth2/default/v1/token
  • oauth.code.challenge.method: Okta code challenge method. Default value S256
  • oauth.oauth.digest.algo: Java hashing algorithm used to verify the code challenge. Default value SHA-256
  • oauth.username.field: The field from Okta identity response to use as the AMI username. Default value email
  • oauth.ami.isadmin.field: The field from Okta identity response use to identity an AMI admin user (Recommended).
  • oauth.ami.isadmin.values: Comma delimited list of AMI admins. If the value of the isadmin field matches any of the values, the user gets AMI admin privileges. Otherwise the user will be in user mode.
  • oauth.ami.isdev.field: The field from Okta identity response use to identity an AMI dev user (Recommended).
  • oauth.ami.isdev.values: Comma delimited list of AMI devs. If the value of the isdev field matches any of the values, the user gets AMI dev privileges.
  • oauth.debug: For detailed logging. Default value false
  • oauth.session.check.period.seconds: Controls polling frequency for a refresh token and also the frequency of the reaper thread to check on the SSO session. Defaults to 60 seconds.