io.undertow.security.api.AuthenticationMechanism Maven / Gradle / Ivy
/*
* JBoss, Home of Professional Open Source.
* Copyright 2014 Red Hat, Inc., and individual contributors
* as indicated by the @author tags.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package io.undertow.security.api;
import io.undertow.server.HttpServerExchange;
/**
* The interface to be implemented by a single authentication mechanism.
*
* The implementation of this interface are assumed to be stateless, if there is a need to share state between the authenticate
* and handleComplete calls then it should be held in the HttpServerExchange.
*
* As an in-bound request is received the authenticate method is called on each mechanism in turn until one of the following
* occurs: - - A mechanism successfully authenticates the incoming request. - A mechanism attempts but fails to authenticate the
* request. - The list of mechanisms is exhausted.
*
* This means that if the authenticate method is called on a mechanism it should assume it is required to check if it can
* actually authenticate the incoming request, anything that would prevent it from performing the check would have already
* stopped the authenticate method from being called.
*
* Authentication is allowed to proceed if either authentication was required AND one handler authenticated the request or it is
* allowed to proceed if it is not required AND no handler failed to authenticate the request.
*
* The handleComplete methods are used as the request processing is returning up the chain, primarily these are used to
* challenge the client to authenticate but where supported by the mechanism they could also be used to send mechanism specific
* updates back with a request.
*
* If a mechanism successfully authenticated the incoming request then only the handleComplete method on that mechanism is
* called.
*
* If any mechanism failed or if authentication was required and no mechanism succeeded in authenticating the request then
* handleComplete will be called for all mechanisms.
*
* Finally if authentication was not required handleComplete will not be called for any of the mechanisms.
*
* The mechanisms will need to double check why handleComplete is being called, if the request was authenticated then they
* should do nothing unless the mechanism has intermediate state to send back. If the request was not authenticated then a
* challenge should be sent.
*
* @author Stuart Douglas
* @author Darran Lofthouse
*/
public interface AuthenticationMechanism {
/**
* Perform authentication of the request. Any potentially blocking work should be performed in the handoff executor provided
*
* @param exchange The exchange
* @return
*/
AuthenticationMechanismOutcome authenticate(final HttpServerExchange exchange,
final SecurityContext securityContext);
/**
* Send an authentication challenge to the remote client.
*
* The individual mechanisms should update the response headers and body of the message as appropriate however they should
* not set the response code, instead that should be indicated in the {@link ChallengeResult} and the most appropriate
* overall response code will be selected.
*
* This method should not return null
.
*
* @param exchange The exchange
* @param securityContext The security context
* @return A {@link ChallengeResult} indicating if a challenge was sent and the desired response code.
*/
ChallengeResult sendChallenge(final HttpServerExchange exchange, final SecurityContext securityContext);
/**
* The AuthenticationOutcome is used by an AuthenticationMechanism to indicate the outcome of the call to authenticate, the
* overall authentication process will then used this along with the current AuthenticationState to decide how to proceed
* with the current request.
*/
enum AuthenticationMechanismOutcome {
/**
* Based on the current request the mechanism has successfully performed authentication.
*/
AUTHENTICATED,
/**
* The mechanism did not attempt authentication on this request, most likely due to not discovering any applicable
* security tokens for this mechanisms in the request.
*/
NOT_ATTEMPTED,
/**
* The mechanism attempted authentication but it did not complete, this could either be due to a failure validating the
* tokens from the client or it could be due to the mechanism requiring at least one additional round trip with the
* client - either way the request will return challenges to the client.
*/
NOT_AUTHENTICATED;
}
/**
* Simple class to wrap the result of requesting a mechanism sends it's challenge.
*/
class ChallengeResult {
public static final ChallengeResult NOT_SENT = new ChallengeResult(false);
private final boolean challengeSent;
private final Integer statusCode;
public ChallengeResult(final boolean challengeSent, final Integer statusCode) {
this.statusCode = statusCode;
this.challengeSent = challengeSent;
}
public ChallengeResult(final boolean challengeSent) {
this(challengeSent, null);
}
/**
* Obtain the response code desired by this mechanism for the challenge.
*
* Where multiple mechanisms are in use concurrently all of the requested response codes will be checked and the most
* suitable one selected. If no specific response code is required any value less than 0 can be set.
*
* @return The desired response code or null if no code specified.
*/
public Integer getDesiredResponseCode() {
return statusCode;
}
/**
* Check if the mechanism did send a challenge.
*
* Some mechanisms do not send a challenge and just rely on the correct information to authenticate a user being
* available in the request, in that case it would be normal for the mechanism to set this to false.
*
* @return true if a challenge was sent, false otherwise.
*/
public boolean isChallengeSent() {
return challengeSent;
}
}
}