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

com.rapidclipse.framework.security.authentication.SequenceAuthenticator Maven / Gradle / Ivy

There is a newer version: 14.0.0
Show newest version
/*
 * Copyright (C) 2013-2023 by XDEV Software, All Rights Reserved.
 *
 * This file is part of the RapidClipse Application Platform (RAP).
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see .
 *
 * SPDX-License-Identifier: AGPL-3.0-or-later
 *
 * Contributors:
 *     XDEV Software - initial API and implementation
 */
package com.rapidclipse.framework.security.authentication;

/**
 * An implementation of {@link Authenticator} that wraps a sequence of passed authenticators in a new instance.
 * For the exact behaviour, see {@link #authenticate(Object)}.
 *
 * @author XDEV Software (TM)
 *
 * @param 
 *            the type of the credentials instance to be authenticated.
 * @param 
 *            the type of the result/response instance to be returned upon an authentication attempt.
 */
public final class SequenceAuthenticator implements Authenticator
{
	///////////////////////////////////////////////////////////////////////////
	// static methods //
	///////////////////
	
	/**
	 * Constructor method that does validation and implementation detail encapsulation of the actual constructor.
	 * 

* The passed array of {@link Authenticator} instances may neither be null nor empty. * The created instance uses a copy of the passed array internally to avoid any later side effects. * * @param authenticators * the authenticators to be evaluated in order. * @return a new authenticator instance wrapping a sequence of other {@link Authenticator} instances. * @throws IllegalArgumentException * if the passed array is empty. * @see #authenticate(Object) */ @SafeVarargs public static final SequenceAuthenticator New(final Authenticator... authenticators) throws IllegalArgumentException { // at least one authenticator must be present if(authenticators.length < 1) { throw new IllegalArgumentException(); } // defensive copy of a usually tiny array, usually only once per application, is negligible. return new SequenceAuthenticator<>(authenticators.clone()); } /////////////////////////////////////////////////////////////////////////// // instance fields // //////////////////// /** * The sequence of {@link Authenticator} instances used by the {@link SequenceAuthenticator} instance. */ private final Authenticator[] authenticators; /////////////////////////////////////////////////////////////////////////// // constructors // ///////////////// /** * Constructor might change in the future (maybe to using a collection), so it gets hidden as the implementation * detail it is. * * @param authenticators * the authenticators to be evaluated in order. */ SequenceAuthenticator(final Authenticator[] authenticators) { super(); this.authenticators = authenticators; // null-check to be done by implementation-private calling context. } /////////////////////////////////////////////////////////////////////////// // declared methods // ///////////////////// /** * Returns a defensive copy of the internally used authenticator sequence. * * @return the wrapped authenticators. */ public final Authenticator[] getAuthenticators() { // defensive copy of a usually tiny array, usually never called, is negligible. return this.authenticators.clone(); } /////////////////////////////////////////////////////////////////////////// // override methods // ///////////////////// /** * Calling this method internally delegates to the same method of the passed authenticators in the exact same * order as they have been passed at construction time. If an internally called authenticator produces one of * the following results, the delegated authentication attempt is deemed a failure and the next authenticator * in the sequence is used: *

    *
  • returned value of null.
  • *
  • returned value equal to {@link Boolean#FALSE}.
  • *
  • an {@link AuthenticationFailedException} occured.
  • *
* If the last authenticator is reached, it is called directly without any wrapping logic, * returning any value and passing any exception it might throw. *

* This effectively creates a multi-attempt {@link Authenticator} that succeed on the first success of one of its * subsidiary authenticators. * * @param credentials * the credentials to be evaluated for the authentication. * @return the first return value not deemed to indicate a failure or whatever the last authenticator returns. * @throws AuthenticationFailedException * if the last authenticator throws an {@link AuthenticationFailedException}. */ @Override public final R authenticate(final C credentials) throws AuthenticationFailedException { // iterate over all non-last authenticators final int lastIndex = this.authenticators.length - 1; for(int i = 0; i < lastIndex; i++) { try { // first attempt to authenticate the passed credentials final R firstResult = this.authenticators[i].authenticate(credentials); if(firstResult != null && !Boolean.FALSE.equals(firstResult)) { return firstResult; } // otherwise (null or FALSE), fall through to second attempt } catch(final AuthenticationFailedException e) { // for a business-logical failed authentication, fall through to the next attempt. } catch(final Throwable t) { // pass through any other throwable throw t; } } // rely on last authenticator for the final attempt to prevent context-specific logic in here return this.authenticators[lastIndex].authenticate(credentials); } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy