Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[ELY-521] And related changes following ServerAuthenticationContext Clean Up #430

Merged
merged 7 commits into from May 5, 2016
Expand Up @@ -1181,6 +1181,9 @@ public interface ElytronMessages extends BasicLogger {
@Message(id = 6005, value= "Attachments are not supported on this scope.")
UnsupportedOperationException noAttachmentSupport();

@Message(id = 6006, value = "An authorization check for user '%s' failed using mechanism '%s'.")
String authorizationFailed(String username, String mechanismName);

/* asn1 package */

@Message(id = 7001, value = "Unrecognized encoding algorithm")
Expand Down
Expand Up @@ -38,6 +38,7 @@
import org.wildfly.security.http.HttpConstants;
import org.wildfly.security.http.HttpServerAuthenticationMechanism;
import org.wildfly.security.http.HttpServerAuthenticationMechanismFactory;
import org.wildfly.security.http.util.SecurityIdentityServerMechanismFactory;
import org.wildfly.security.password.interfaces.ClearPassword;
import org.wildfly.security.password.interfaces.DigestPassword;

Expand All @@ -54,7 +55,7 @@ public final class HttpAuthenticationFactory extends AbstractMechanismAuthentica
}

HttpServerAuthenticationMechanism doCreate(final String name, final CallbackHandler callbackHandler, final UnaryOperator<HttpServerAuthenticationMechanismFactory> factoryTransformation) throws HttpAuthenticationException {
return factoryTransformation.apply(getFactory()).createAuthenticationMechanism(name, Collections.emptyMap(), callbackHandler);
return new SecurityIdentityServerMechanismFactory(factoryTransformation.apply(getFactory())).createAuthenticationMechanism(name, Collections.emptyMap(), callbackHandler);
}

Collection<String> getAllSupportedMechNames() {
Expand Down
Expand Up @@ -737,7 +737,7 @@ private void handleOne(final Callback[] callbacks, final int idx) throws IOExcep
final X500Principal principal = evidence.getPrincipal();
if (principal != null) {
setAuthenticationPrincipal(principal);
final boolean authorized = verifyEvidence(evidence);
final boolean authorized = verifyEvidence(evidence) && authorize();
authorizationCallback.setAuthorized(authorized);
if (authorized) {
// cache identity
Expand Down
Expand Up @@ -18,6 +18,8 @@

package org.wildfly.security.http;

import static org.wildfly.security.http.HttpConstants.SECURITY_IDENTITY;

import static org.wildfly.security._private.ElytronMessages.log;
import static org.wildfly.security.http.HttpConstants.FORBIDDEN;
import static org.wildfly.security.http.HttpConstants.OK;
Expand Down Expand Up @@ -180,9 +182,11 @@ public void authenticationInProgress(HttpServerMechanismsResponder responder) {
}

@Override
public void authenticationComplete(SecurityIdentity securityIdentity, HttpServerMechanismsResponder responder) {
public void authenticationComplete(HttpServerMechanismsResponder responder) {
authenticated = true;
httpExchangeSpi.authenticationComplete(securityIdentity, currentMechanism.getMechanismName());
httpExchangeSpi.authenticationComplete(
currentMechanism.getNegotiationProperty(SECURITY_IDENTITY, SecurityIdentity.class),
currentMechanism.getMechanismName());
successResponder = responder;
}

Expand Down
9 changes: 9 additions & 0 deletions src/main/java/org/wildfly/security/http/HttpConstants.java
Expand Up @@ -27,6 +27,15 @@ public class HttpConstants {
private HttpConstants() {
}

/*
* Negotiated Properties
*/

/**
* The property which holds the negotiated security identity after a successful HTTP server-side authentication.
*/
public static final String SECURITY_IDENTITY = "wildfly.http.security-identity";

/*
* Header Fields
*/
Expand Down
Expand Up @@ -43,6 +43,37 @@ public interface HttpServerAuthenticationMechanism {
*/
void evaluateRequest(HttpServerRequest request) throws HttpAuthenticationException;

/**
* Get the property negotiated as a result of authentication.
*
* Mechanisms only make properties available after indicating a successful authentication has completed.
*
* @param propertyName the name of the property.
* @return the value of the property or {@code null} if the specified property is not available.
*/
default Object getNegotiatedProperty(String propertyName) {
return null;
}

/**
* Get the strongly typed property negotiated as a result of authentication.
*
* Mechanisms only make properties available after indicating a successful authentication has completed.
*
* Note: This form of the mechanism will also return {@code null} if the property is set but is of a different type.
*
* @param propertyName the name of the property.
* @param type the expected type of the property.
* @return the value of the property or {@code null} if the specified property is not available or is of a different type..
*/
default <T> T getNegotiationProperty(String propertyName, Class<T> type) {
Object property = getNegotiatedProperty(propertyName);
if (property != null && type.isInstance(property)) {
return type.cast(property);
}
return null;
}

/**
* Dispose of any resources currently held by this authentication mechanism.
*/
Expand Down
13 changes: 9 additions & 4 deletions src/main/java/org/wildfly/security/http/HttpServerRequest.java
Expand Up @@ -89,20 +89,25 @@ default void noAuthenticationInProgress() {
/**
* Notification that authentication is now complete.
*
* @param securityIdentity the {@link SecurityIdentity} established as a result of this authentication.
* After this point the framework will perform an authorization check for the authenticated user and if successful establish
* the identity of the request.
*
* @param responder a {@link HttpServerMechanismsResponder} that can send a response.
*/
void authenticationComplete(SecurityIdentity securityIdentity, final HttpServerMechanismsResponder responder);
void authenticationComplete(final HttpServerMechanismsResponder responder);

/**
* Notification that authentication is now complete.
*
* After this point the framework will perform an authorization check for the authenticated user and if successful establish
* the identity of the request.
*
* If this form is called no response is expected from this mechanism.
*
* @param securityIdentity the {@link SecurityIdentity} established as a result of this authentication.
*/
default void authenticationComplete(SecurityIdentity securityIdentity) {
authenticationComplete(securityIdentity, null);
default void authenticationComplete() {
authenticationComplete(null);
}

/**
Expand Down
Expand Up @@ -40,11 +40,11 @@
import javax.security.auth.callback.CallbackHandler;
import javax.security.auth.callback.NameCallback;
import javax.security.auth.callback.UnsupportedCallbackException;
import javax.security.sasl.AuthorizeCallback;
import javax.security.sasl.RealmCallback;

import org.wildfly.security.auth.callback.AuthenticationCompleteCallback;
import org.wildfly.security.auth.callback.EvidenceVerifyCallback;
import org.wildfly.security.auth.callback.SecurityIdentityCallback;
import org.wildfly.security.evidence.PasswordGuessEvidence;
import org.wildfly.security.http.HttpAuthenticationException;
import org.wildfly.security.http.HttpServerAuthenticationMechanism;
Expand Down Expand Up @@ -122,11 +122,17 @@ public void evaluateRequest(final HttpServerRequest request) throws HttpAuthenti
try {
String username = usernameChars.toString();
if (authenticate(username, passwordChars.array())) {
SecurityIdentityCallback securityIdentityCallback = new SecurityIdentityCallback();
callbackHandler.handle(new Callback[] { AuthenticationCompleteCallback.SUCCEEDED, securityIdentityCallback });
if (authorize(username)) {
callbackHandler.handle(new Callback[] { AuthenticationCompleteCallback.SUCCEEDED });

request.authenticationComplete();
return;
} else {
callbackHandler.handle(new Callback[] { AuthenticationCompleteCallback.FAILED });
request.authenticationFailed(log.authorizationFailed(username, BASIC_NAME), response -> prepareResponse(() -> getHostName(request), response));
return;
}

request.authenticationComplete(securityIdentityCallback.getSecurityIdentity());
return;
} else {
callbackHandler.handle(new Callback[] { AuthenticationCompleteCallback.FAILED });
request.authenticationFailed(log.authenticationFailed(username, BASIC_NAME), response -> prepareResponse(() -> getHostName(request), response));
Expand Down Expand Up @@ -174,6 +180,20 @@ private boolean authenticate(String username, char[] password) throws HttpAuthen
}
}

private boolean authorize(String username) throws HttpAuthenticationException {
AuthorizeCallback authorizeCallback = new AuthorizeCallback(username, username);

try {
callbackHandler.handle(new Callback[] {authorizeCallback});

return authorizeCallback.isAuthorized();
} catch (UnsupportedCallbackException e) {
return false;
} catch (IOException e) {
throw new HttpAuthenticationException(e);
}
}

private String getHostName(HttpServerRequest request) {
return request.getFirstRequestHeaderValue(HOST);
}
Expand Down
Expand Up @@ -80,7 +80,7 @@ public void evaluateRequest(HttpServerRequest request) throws HttpAuthentication

if (callback.isAuthorized()) try {
MechanismUtil.handleCallbacks(CLIENT_CERT_NAME, callbackHandler, AuthenticationCompleteCallback.SUCCEEDED);
request.authenticationComplete(null);
request.authenticationComplete();
} catch (AuthenticationMechanismException e) {
throw e.toHttpAuthenticationException();
} catch (UnsupportedCallbackException ignored) {
Expand Down
Expand Up @@ -35,7 +35,6 @@

import javax.net.ssl.SSLSession;

import org.wildfly.security.auth.server.SecurityIdentity;
import org.wildfly.security.http.HttpAuthenticationException;
import org.wildfly.security.http.HttpScope;
import org.wildfly.security.http.HttpServerAuthenticationMechanism;
Expand Down Expand Up @@ -97,6 +96,17 @@ public void evaluateRequest(final HttpServerRequest request) throws HttpAuthenti
}
}

@Override
public Object getNegotiatedProperty(String propertyName) {
return mechanism.getNegotiatedProperty(propertyName);
}

@Override
public <T> T getNegotiationProperty(String propertyName, Class<T> type) {
return mechanism.getNegotiationProperty(propertyName, type);
}


private HttpServerMechanismsResponder wrap(final HttpServerMechanismsResponder toWrap) {
return toWrap != null ? (HttpServerResponse r) -> AccessController.doPrivileged((PrivilegedAction<Void>) () -> {
toWrap.sendResponse(r);
Expand Down Expand Up @@ -153,8 +163,8 @@ public void authenticationInProgress(HttpServerMechanismsResponder responder) {
}

@Override
public void authenticationComplete(SecurityIdentity securityIdentity, HttpServerMechanismsResponder responder) {
wrapped.authenticationComplete(securityIdentity, wrap(responder));
public void authenticationComplete(HttpServerMechanismsResponder responder) {
wrapped.authenticationComplete(wrap(responder));
}

@Override
Expand Down
@@ -0,0 +1,125 @@
/*
* JBoss, Home of Professional Open Source.
* Copyright 2016 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 org.wildfly.security.http.util;

import static org.wildfly.security.http.HttpConstants.SECURITY_IDENTITY;

import static org.wildfly.common.Assert.checkNotNullParam;

import java.io.IOException;
import java.util.Map;

import javax.security.auth.callback.Callback;
import javax.security.auth.callback.CallbackHandler;
import javax.security.auth.callback.UnsupportedCallbackException;

import org.wildfly.security.auth.callback.AuthenticationCompleteCallback;
import org.wildfly.security.auth.callback.SecurityIdentityCallback;
import org.wildfly.security.auth.server.SecurityIdentity;
import org.wildfly.security.http.HttpAuthenticationException;
import org.wildfly.security.http.HttpServerAuthenticationMechanism;
import org.wildfly.security.http.HttpServerAuthenticationMechanismFactory;
import org.wildfly.security.http.HttpServerRequest;

/**
*
*
* @author <a href="mailto:darran.lofthouse@jboss.com">Darran Lofthouse</a>
*/
public class SecurityIdentityServerMechanismFactory implements HttpServerAuthenticationMechanismFactory {

private final HttpServerAuthenticationMechanismFactory delegate;

public SecurityIdentityServerMechanismFactory(HttpServerAuthenticationMechanismFactory delegate) {
this.delegate = checkNotNullParam("delegate", delegate);
}

/**
* @see org.wildfly.security.http.HttpServerAuthenticationMechanismFactory#getMechanismNames(java.util.Map)
*/
@Override
public String[] getMechanismNames(Map<String, ?> properties) {
return delegate.getMechanismNames(properties);
}

/**
* @see org.wildfly.security.http.HttpServerAuthenticationMechanismFactory#createAuthenticationMechanism(java.lang.String, java.util.Map, javax.security.auth.callback.CallbackHandler)
*/
@Override
public HttpServerAuthenticationMechanism createAuthenticationMechanism(String mechanismName, Map<String, ?> properties, CallbackHandler callbackHandler) throws HttpAuthenticationException {
SecurityIdentityCallbackHandler securityIdentityCallbackHandler = new SecurityIdentityCallbackHandler(callbackHandler);
final HttpServerAuthenticationMechanism delegate = this.delegate.createAuthenticationMechanism(mechanismName, properties, securityIdentityCallbackHandler);
if (delegate != null) {
return new HttpServerAuthenticationMechanism() {

@Override
public String getMechanismName() {
return delegate.getMechanismName();
}

@Override
public void evaluateRequest(HttpServerRequest request) throws HttpAuthenticationException {
delegate.evaluateRequest(request);
}

@Override
public Object getNegotiatedProperty(String propertyName) {
return SECURITY_IDENTITY.equals(propertyName) ? securityIdentityCallbackHandler.getSecurityIdentity()
: delegate.getNegotiatedProperty(propertyName);
}

};
}
return null;
}

private static class SecurityIdentityCallbackHandler implements CallbackHandler {

private final CallbackHandler delegate;
private SecurityIdentity securityIdentity;

SecurityIdentityCallbackHandler(CallbackHandler delegate) {
this.delegate = delegate;
}

@Override
public void handle(Callback[] callbacks) throws IOException, UnsupportedCallbackException {
Callback[] theCallbacks = callbacks;
SecurityIdentityCallback securityIdentityCallback = null;
for (Callback current : callbacks) {
if (current instanceof AuthenticationCompleteCallback
&& ((AuthenticationCompleteCallback) current).succeeded()) {
theCallbacks = new Callback[callbacks.length + 1];
System.arraycopy(callbacks, 0, theCallbacks, 0, callbacks.length);
theCallbacks[theCallbacks.length - 1] = (securityIdentityCallback = new SecurityIdentityCallback());
}
}

delegate.handle(theCallbacks);
if (securityIdentityCallback != null) {
securityIdentity = securityIdentityCallback.getSecurityIdentity();
}
}

SecurityIdentity getSecurityIdentity() {
return securityIdentity;
}

}

}
4 changes: 2 additions & 2 deletions src/main/java/org/wildfly/security/sasl/WildFlySasl.java
Expand Up @@ -95,9 +95,9 @@ public final class WildFlySasl {
public static final String MECHANISM_QUERY_ALL = "wildfly.sasl.mechanism-query-all";

/**
* The property which holds the negotiated realm identity after a successful SASL server-side authentication.
* The property which holds the negotiated security identity after a successful SASL server-side authentication.
*/
public static final String SECURITY_IDENTITY = "wildfly.sasl.realm-identity";
public static final String SECURITY_IDENTITY = "wildfly.sasl.security-identity";

/**
* The immutable empty names array.
Expand Down