/*
* Copyright 2012-2017 CodeLibs Project and the Others.
*
* 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.codelibs.fess.sso.spnego;
import java.io.File;
import java.util.Enumeration;
import javax.annotation.PostConstruct;
import javax.servlet.FilterConfig;
import javax.servlet.ServletContext;
import javax.servlet.http.HttpServletResponse;
import org.codelibs.core.io.ResourceUtil;
import org.codelibs.fess.app.web.base.login.ActionResponseCredential;
import org.codelibs.fess.app.web.base.login.SpnegoCredential;
import org.codelibs.fess.exception.FessSystemException;
import org.codelibs.fess.exception.SsoLoginException;
import org.codelibs.fess.mylasta.direction.FessConfig;
import org.codelibs.fess.sso.SsoAuthenticator;
import org.codelibs.fess.util.ComponentUtil;
import org.codelibs.spnego.SpnegoFilterConfig;
import org.codelibs.spnego.SpnegoHttpFilter;
import org.codelibs.spnego.SpnegoHttpFilter.Constants;
import org.codelibs.spnego.SpnegoHttpServletResponse;
import org.codelibs.spnego.SpnegoPrincipal;
import org.lastaflute.web.login.credential.LoginCredential;
import org.lastaflute.web.servlet.filter.RequestLoggingFilter;
import org.lastaflute.web.util.LaRequestUtil;
import org.lastaflute.web.util.LaResponseUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class SpnegoAuthenticator implements SsoAuthenticator {
private static final Logger logger = LoggerFactory.getLogger(SpnegoAuthenticator.class);
protected org.codelibs.spnego.SpnegoAuthenticator authenticator = null;
@PostConstruct
public void init() {
if ("spnego".equals(ComponentUtil.getFessConfig().getSsoType())) {
try {
// set some System properties
final SpnegoFilterConfig config = SpnegoFilterConfig.getInstance(new SpengoConfig());
// pre-authenticate
authenticator = new org.codelibs.spnego.SpnegoAuthenticator(config);
} catch (final Exception e) {
throw new FessSystemException("Failed to initialize SPNEGO.", e);
}
}
}
/* (non-Javadoc)
* @see org.codelibs.fess.sso.spnego.SsoAuthenticator#getLoginCredential()
*/
@Override
public LoginCredential getLoginCredential() {
return LaRequestUtil
.getOptionalRequest()
.map(request -> {
final HttpServletResponse response = LaResponseUtil.getResponse();
final SpnegoHttpServletResponse spnegoResponse = new SpnegoHttpServletResponse(response);
// client/caller principal
final SpnegoPrincipal principal;
try {
principal = authenticator.authenticate(request, spnegoResponse);
} catch (final Exception e) {
final String msg = "HTTP Authorization Header=" + request.getHeader(Constants.AUTHZ_HEADER);
logger.error(msg);
throw new SsoLoginException(msg, e);
}
// context/auth loop not yet complete
if (spnegoResponse.isStatusSet()) {
return new ActionResponseCredential(() -> {
throw new RequestLoggingFilter.RequestClientErrorException("Your request is not authorized.",
"401 Unauthorized", HttpServletResponse.SC_UNAUTHORIZED);
});
}
// assert
if (null == principal) {
final String msg = "Principal was null.";
logger.error(msg);
throw new SsoLoginException(msg);
}
if (logger.isDebugEnabled()) {
logger.debug("principal=" + principal);
}
final String[] username = principal.getName().split("@", 2);
return new SpnegoCredential(username[0]);
}).orElseGet(() -> null);
}
protected class SpengoConfig implements FilterConfig {
protected FessConfig fessConfig = ComponentUtil.getFessConfig();
@Override
public String getFilterName() {
return SpnegoAuthenticator.class.getName();
}
@Override
public ServletContext getServletContext() {
throw new UnsupportedOperationException();
}
@Override
public String getInitParameter(final String name) {
if (SpnegoHttpFilter.Constants.LOGGER_LEVEL.equals(name)) {
return fessConfig.getSpnegoLoggerLevel();
} else if (SpnegoHttpFilter.Constants.LOGIN_CONF.equals(name)) {
return getResourcePath(fessConfig.getSpnegoLoginConf());
} else if (SpnegoHttpFilter.Constants.KRB5_CONF.equals(name)) {
return getResourcePath(fessConfig.getSpnegoKrb5Conf());
} else if (SpnegoHttpFilter.Constants.CLIENT_MODULE.equals(name)) {
return fessConfig.getSpnegoLoginClientModule();
} else if (SpnegoHttpFilter.Constants.SERVER_MODULE.equals(name)) {
return fessConfig.getSpnegoLoginServerModule();
} else if (SpnegoHttpFilter.Constants.PREAUTH_USERNAME.equals(name)) {
return fessConfig.getSpnegoPreauthUsername();
} else if (SpnegoHttpFilter.Constants.PREAUTH_PASSWORD.equals(name)) {
return fessConfig.getSpnegoPreauthPassword();
} else if (SpnegoHttpFilter.Constants.ALLOW_BASIC.equals(name)) {
return fessConfig.getSpnegoAllowBasic();
} else if (SpnegoHttpFilter.Constants.ALLOW_UNSEC_BASIC.equals(name)) {
return fessConfig.getSpnegoAllowUnsecureBasic();
} else if (SpnegoHttpFilter.Constants.PROMPT_NTLM.equals(name)) {
return fessConfig.getSpnegoPromptNtlm();
} else if (SpnegoHttpFilter.Constants.ALLOW_LOCALHOST.equals(name)) {
return fessConfig.getSpnegoAllowLocalhost();
} else if (SpnegoHttpFilter.Constants.ALLOW_DELEGATION.equals(name)) {
return fessConfig.getSpnegoAllowDelegation();
}
return null;
}
protected String getResourcePath(final String path) {
final File file = ResourceUtil.getResourceAsFileNoException(path);
if (file != null) {
return file.getAbsolutePath();
}
return null;
}
@Override
public Enumeration<String> getInitParameterNames() {
throw new UnsupportedOperationException();
}
}
}