Skip to content
Architecture > Authentication

Custom Authentication

Overview

It is necessary to authenticate users to ensure that they have valid credentials and have been granted access to your application. 3forge AMI has support for SSO Plugins. SSO Plugins are authentication plugins for 3forge AMI Applications that need to support either Single Sign On or Federated Identity, where SSO provides support for single access to multiple systems in one organization and Federated Identity provides that for multiple organizations.

This document will provide the basic template you will need to set up your own Java 3forge AMI SSO Plugin.

You will need to implement a Java interface and include the properties provided below.

Java interface

com.f1.ami.web.AmiWebSSOPlugin

package com.f1.ami.web;

import com.f1.ami.amicommon.AmiPlugin;
import com.f1.ami.web.auth.AmiAuthUser;
import com.f1.http.HttpRequestResponse;
import com.f1.suite.web.HttpRequestAction;

/**
 * 1) Set the sso.plugin.class property to point to an implementation of this class
 * 2) Set the ami.web.index.html.file property to the URL that is associated with buildAuthRequest(...) method
 * 3) getExpectedResponsePath() must return URL associated with processResponse(...) method
 * 4) When users access the index file (from step 1) buildAuthRequest(..) is called and the user's browser is redirected to the returned URL (usually the IDP)
 * 5) After the IDP has authenticated, the IDP should then redirect the user's browser to the getExpectedResposnePath() URL (from step 2)
 * 6) processResponse(...) is called and should return an AmiUathUser that will be passed to the AMI dashboard
 */
public interface AmiWebSSOPlugin extends AmiPlugin {

    /**
     *
     * Use the ami.web.index.html.file to associate the URL that will cause this method to be invoked. This method should inspect the HTTP request and formulate a fully qualified
     * URL that will be sent to the IDP.
     * Note, thistask method should return the URL as specified in getExpectedResponsePath() if it's determined,based on the supplied request that the user is already authenticated
     *
     * @param req
     *            the http request
     * @return a URL that the user's browser will be redirected to
     */
    String buildAuthRequest(HttpRequestResponse req) throws Exception;

    /**
     * @return the URL that the processResponse(...) method is associated with. This method is called once at startup. Hence, return value is really a constant
     */
    String getExpectedResponsePath();

    /**
     *
     * @param req
     *            the http request
     * @return null if not allowed. See com.f1.ami.web.auth.BasicAmiAuthUser for convenience class
     * @throws Exception
     *             if there was an error, the user will not be permitted to login
     */
    AmiAuthUser processResponse(HttpRequestAction req) throws Exception;

}

Properties

1
2
3
sso.plugin.class=fully_qualified_class_name
ami.web.index.html.file=index2.htm
web.logged.out.url=/loggedout.htm

Example

Example Java-Code:

package com.company.ami;

import java.util.HashMap;
import java.util.Map;

import com.f1.ami.web.auth.AmiAuthUser;
import com.f1.ami.web.auth.BasicAmiAuthUser;
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 MySSOPlugin implements AmiWebSSOPlugin {

    @Override
    public void init(ContainerTools tools, PropertyController props) {
        // TODO Auto-generated method stub
        System.out.println("Initializing My SSO Plugin");
    }

    @Override
    public String getPluginId() {
        return "SampleSSOPlugin";
    }

    @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();

        // 1) Here you build your Authorization Request for your Identity Provider
        // ... Code here

        // 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");

        String redirectUrlForLogin = "https://identityProvider/login?{login parameters}&expectedResponsePath=" + this.getExpectedResponsePath();
        //// End code
        return redirectUrlForLogin;
    }

    @Override
    public AmiAuthUser processResponse(HttpRequestAction req) throws Exception {
        HttpRequestResponse request = req.getRequest();
        Map<String, String> header = request.getHeader();
        Map<String, String> cookies = request.getCookies();
        Map<String, String> params = request.getParams();

        // 2) Ensure Identity Provider Authorized the User
        // ... Code here
        ////

        // If the user is valid:
        // 3) Add user attributes to authAttributes;
        Map<String, Object> authAttributes = new HashMap<String, Object>();
        // ... Code here
        ////
        return new BasicAmiAuthUser("username", authAttributes);
    }

    @Override
    public String getExpectedResponsePath() {
        return "login_redirect_url";
    }
}

Example Configuration:

1
2
3
sso.plugin.class=com.company.ami.MySSOPlugin
ami.web.index.html.file=index.htm
web.logged.out.url=/loggedout.htm

Reserved Paths

NOTE: Below is a list of url paths reserved for use by 3forge. Avoid using any of them as your expected response path to avoid unexpected behavior.

  • 3forge_hello (e.g. hostname:33332/3forge_hello)
  • 3forge_goodbye
  • 3forge_sessions
  • own_headless
  • logout
  • login
  • resources
  • run
  • modcount
  • get_custom_login_image