blob: 3363c201fa4bacd0a2a9624b9bc501d62623ab0d [file] [log] [blame]
/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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.apache.cxf.interceptor.security;
import java.security.PrivilegedAction;
import java.util.ArrayList;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.security.auth.Subject;
import javax.security.auth.callback.Callback;
import javax.security.auth.callback.CallbackHandler;
import javax.security.auth.callback.NameCallback;
import javax.security.auth.login.Configuration;
import javax.security.auth.login.LoginContext;
import javax.security.auth.login.LoginException;
import org.apache.cxf.common.logging.LogUtils;
import org.apache.cxf.interceptor.InterceptorChain;
import org.apache.cxf.interceptor.security.callback.CallbackHandlerProvider;
import org.apache.cxf.interceptor.security.callback.CallbackHandlerProviderAuthPol;
import org.apache.cxf.interceptor.security.callback.CallbackHandlerProviderUsernameToken;
import org.apache.cxf.message.Message;
import org.apache.cxf.phase.AbstractPhaseInterceptor;
import org.apache.cxf.phase.Phase;
import org.apache.cxf.security.SecurityContext;
public class JAASLoginInterceptor extends AbstractPhaseInterceptor<Message> {
public static final String ROLE_CLASSIFIER_PREFIX = "prefix";
public static final String ROLE_CLASSIFIER_CLASS_NAME = "classname";
private static final Logger LOG = LogUtils.getL7dLogger(JAASLoginInterceptor.class);
private String contextName = "";
private Configuration loginConfig;
private String roleClassifier;
private String roleClassifierType = ROLE_CLASSIFIER_PREFIX;
private boolean reportFault;
private boolean useDoAs = true;
private List<CallbackHandlerProvider> callbackHandlerProviders;
private boolean allowAnonymous = true;
private boolean allowNamedPrincipals;
public JAASLoginInterceptor() {
this(Phase.UNMARSHAL);
}
public JAASLoginInterceptor(String phase) {
super(phase);
this.callbackHandlerProviders = new ArrayList<>();
this.callbackHandlerProviders.add(new CallbackHandlerProviderAuthPol());
this.callbackHandlerProviders.add(new CallbackHandlerProviderUsernameToken());
}
public void setContextName(String name) {
contextName = name;
}
public String getContextName() {
return contextName;
}
/**
* @deprecated replaced by {@link #setRoleClassifier(String)}
* @param name
*/
@Deprecated
public void setRolePrefix(String name) {
setRoleClassifier(name);
}
public void setRoleClassifier(String value) {
roleClassifier = value;
}
public String getRoleClassifier() {
return roleClassifier;
}
public void setRoleClassifierType(String value) {
if (!ROLE_CLASSIFIER_PREFIX.equals(value)
&& !ROLE_CLASSIFIER_CLASS_NAME.equals(value)) {
throw new IllegalArgumentException("Unsupported role classifier");
}
roleClassifierType = value;
}
public String getRoleClassifierType() {
return roleClassifierType;
}
public void setReportFault(boolean reportFault) {
this.reportFault = reportFault;
}
public void setUseDoAs(boolean useDoAs) {
this.useDoAs = useDoAs;
}
private CallbackHandler getFirstCallbackHandler(Message message) {
for (CallbackHandlerProvider cbp : callbackHandlerProviders) {
CallbackHandler cbh = cbp.create(message);
if (cbh != null) {
return cbh;
}
}
return null;
}
public void handleMessage(final Message message) {
if (allowNamedPrincipals) {
SecurityContext sc = message.get(SecurityContext.class);
if (sc != null && sc.getUserPrincipal() != null
&& sc.getUserPrincipal().getName() != null) {
return;
}
}
CallbackHandler handler = getFirstCallbackHandler(message);
if (handler == null && !allowAnonymous) {
throw new AuthenticationException("Authentication required but no authentication information was supplied");
}
try {
LoginContext ctx = new LoginContext(getContextName(), null, handler, loginConfig);
ctx.login();
Subject subject = ctx.getSubject();
String name = getUsername(handler);
message.put(SecurityContext.class, createSecurityContext(name, subject));
// Run the further chain in the context of this subject.
// This allows other code to retrieve the subject using pure JAAS
if (useDoAs) {
Subject.doAs(subject, new PrivilegedAction<Void>() {
@Override
public Void run() {
InterceptorChain chain = message.getInterceptorChain();
if (chain != null) {
message.put("suspend.chain.on.current.interceptor", Boolean.TRUE);
chain.doIntercept(message);
}
return null;
}
});
}
} catch (LoginException ex) {
String errorMessage = "Authentication failed: " + ex.getMessage();
LOG.log(Level.FINE, errorMessage, ex);
if (reportFault) {
AuthenticationException aex = new AuthenticationException(errorMessage);
aex.initCause(ex);
throw aex;
}
throw new AuthenticationException("Authentication failed (details can be found in server log)");
}
}
private String getUsername(CallbackHandler handler) {
if (handler == null) {
return null;
}
try {
NameCallback usernameCallBack = new NameCallback("user");
handler.handle(new Callback[]{usernameCallBack });
return usernameCallBack.getName();
} catch (Exception e) {
return null;
}
}
protected CallbackHandler getCallbackHandler(String name, String password) {
return new NamePasswordCallbackHandler(name, password);
}
protected SecurityContext createSecurityContext(String name, Subject subject) {
if (getRoleClassifier() != null) {
return new RolePrefixSecurityContextImpl(subject, getRoleClassifier(),
getRoleClassifierType());
}
return new DefaultSecurityContext(name, subject);
}
public Configuration getLoginConfig() {
return loginConfig;
}
public void setLoginConfig(Configuration loginConfig) {
this.loginConfig = loginConfig;
}
public List<CallbackHandlerProvider> getCallbackHandlerProviders() {
return callbackHandlerProviders;
}
public void setCallbackHandlerProviders(List<CallbackHandlerProvider> callbackHandlerProviders) {
this.callbackHandlerProviders.clear();
this.callbackHandlerProviders.addAll(callbackHandlerProviders);
}
public void addCallbackHandlerProviders(List<CallbackHandlerProvider> callbackHandlerProviders2) {
this.callbackHandlerProviders.addAll(callbackHandlerProviders2);
}
public void setAllowAnonymous(boolean allowAnonymous) {
this.allowAnonymous = allowAnonymous;
}
public void setAllowNamedPrincipals(boolean allowNamedPrincipals) {
this.allowNamedPrincipals = allowNamedPrincipals;
}
}