All Downloads are FREE. Search and download functionalities are using the official Maven repository.

io.continual.http.app.servers.endpoints.AuthList Maven / Gradle / Ivy

There is a newer version: 0.3.16
Show newest version
package io.continual.http.app.servers.endpoints;

import java.util.LinkedList;

import org.json.JSONObject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import io.continual.http.app.servers.endpoints.TypicalRestApiEndpoint.Authenticator;
import io.continual.http.service.framework.context.CHttpRequestContext;
import io.continual.iam.IamAuthLog;
import io.continual.iam.IamService;
import io.continual.iam.credentials.ApiKeyCredential;
import io.continual.iam.credentials.JwtCredential;
import io.continual.iam.credentials.JwtCredential.InvalidJwtToken;
import io.continual.iam.credentials.UsernamePasswordCredential;
import io.continual.iam.exceptions.IamSvcException;
import io.continual.iam.identity.Identity;
import io.continual.iam.impl.common.ApiKeyAuthHelper;
import io.continual.iam.impl.common.BasicAuthHelper;
import io.continual.iam.impl.common.HeaderReader;

/**
 * A list of authenticators which is itself an authenticator.
 *
 * @param 
 */
class AuthList implements Authenticator
{
	public static final String kSetting_ContinualProductTag = "apiKeyProductTag";
	public static final String kContinualProductTag = "continual";

	/**
	 * Instantiate the standard auth list
	 * @param settings Settings used to configure the authenticators
	 */
	public AuthList ( JSONObject settings )
	{
		fAuthenticators = new LinkedList<>();

		// API key...
		addAuthenticator ( new Authenticator ()
		{
			@Override
			public I authenticate ( IamService am, final CHttpRequestContext context ) throws IamSvcException
			{
				final String systag = settings.optString ( kSetting_ContinualProductTag, kContinualProductTag );

				I authUser = null;
				final ApiKeyCredential creds = ApiKeyAuthHelper.readApiKeyCredential ( settings, new CHttpHeaderReader ( context ), systag );
				if ( creds != null )
				{
					authUser = am.getIdentityDb ().authenticate ( creds );
					if ( authUser != null )
					{
						IamAuthLog.authenticationEvent ( authUser.getId (), "API Key", context.request ().getBestRemoteAddress () );
					}
				}

				return authUser;
			}
		} );

		// JWT...
		addAuthenticator ( new Authenticator ()
		{
			@Override
			public I authenticate ( IamService am, final CHttpRequestContext context ) throws IamSvcException
			{
				I authUser = null;
				try
				{
					JwtCredential cred = null;

					// we normally pick up the JWT token from the Auth/bearer header.
					final String authHeader = context.request ().getFirstHeader ( "Authorization" );
					if ( authHeader != null && authHeader.startsWith ( "Bearer " ) )
					{
						final String[] parts = authHeader.split ( " " );
						if ( parts.length == 2 )
						{
							cred = JwtCredential.fromHeader ( authHeader );
						}
					}
					
					// ... but we also support the token as a parameter to support some REST API
					// use cases, like background data loads
					if ( cred == null )
					{
						final String queryParam = context.request ().getParameter ( "jwt", null );
						if ( queryParam != null )
						{
							cred = new JwtCredential ( queryParam );
						}
					}

					if ( cred != null )
					{
						authUser = am.getIdentityDb ().authenticate ( cred );
						if ( authUser != null )
						{
							IamAuthLog.authenticationEvent ( authUser.getId (), "JWT", context.request ().getBestRemoteAddress () );
						}
					}
				}
				catch ( InvalidJwtToken e )
				{
					// ignore, can't authenticate this way
					log.info ( "Invalid token: " + e.getMessage () );
				}
				return authUser;
			}
		} );

		// username/password...
		addAuthenticator ( new Authenticator ()
		{
			@Override
			public I authenticate ( IamService am, final CHttpRequestContext context ) throws IamSvcException
			{
				I authUser = null;
				final UsernamePasswordCredential upc = BasicAuthHelper.readUsernamePasswordCredential ( new CHttpHeaderReader ( context ) );
				if ( upc != null )
				{
					authUser = am.getIdentityDb().authenticate ( upc );
					if ( authUser != null )
					{
						IamAuthLog.authenticationEvent ( authUser.getId (), "Username/Password", context.request ().getBestRemoteAddress () );
					}
				}
				return authUser;
			}
		} );
	}

	/**
	 * Add an authenticator to this authenticator list
	 * @param a an authenticator
	 * @return this authenticator list
	 */
	public synchronized AuthList addAuthenticator ( Authenticator a )
	{
		fAuthenticators.add ( a );
		return this;
	}
	
	/**
	 * authenticate
	 */
	@Override
	public synchronized I authenticate ( IamService am, CHttpRequestContext context ) throws IamSvcException
	{
		for ( Authenticator inner : fAuthenticators )
		{
			I result = inner.authenticate ( am, context );
			if ( result != null ) return result;
		}
		return null;
	}

	private final LinkedList> fAuthenticators;

	private static class CHttpHeaderReader implements HeaderReader
	{
		public CHttpHeaderReader ( CHttpRequestContext context )
		{
			fContext = context;
		}

		@Override
		public String getFirstHeader ( String header )
		{
			return fContext.request ().getFirstHeader ( header );
		}

		private final CHttpRequestContext fContext;
	}


	private static final Logger log = LoggerFactory.getLogger ( AuthList.class );
}