#571 add SsoAuthenticator
This commit is contained in:
parent
692e02fcda
commit
3eeb4957c9
14 changed files with 467 additions and 231 deletions
|
@ -0,0 +1,36 @@
|
|||
/*
|
||||
* Copyright 2012-2016 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.app.web.base.login;
|
||||
|
||||
import java.util.Collections;
|
||||
|
||||
public class EmptyLoginCredential implements LoginCredential {
|
||||
|
||||
@Override
|
||||
public void validate() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getId() {
|
||||
return "empty";
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getResource() {
|
||||
return Collections.emptyMap();
|
||||
}
|
||||
|
||||
}
|
|
@ -175,8 +175,8 @@ public class FessLoginAssist extends TypicalLoginAssist<String, FessUserBean, Fe
|
|||
}
|
||||
}
|
||||
return doFindLoginUser(username, encryptPassword(password));
|
||||
} else if (credential instanceof SSOLoginCredential) {
|
||||
final String username = ((SSOLoginCredential) credential).getUsername();
|
||||
} else if (credential instanceof SsoLoginCredential) {
|
||||
final String username = ((SsoLoginCredential) credential).getUsername();
|
||||
if (!fessConfig.isAdminUser(username)) {
|
||||
return ComponentUtil.getLdapManager().login(username);
|
||||
}
|
||||
|
|
|
@ -17,12 +17,12 @@ package org.codelibs.fess.app.web.base.login;
|
|||
|
||||
import org.dbflute.util.DfCollectionUtil;
|
||||
|
||||
public class SSOLoginCredential implements LoginCredential {
|
||||
public class SsoLoginCredential implements LoginCredential {
|
||||
private final String username;
|
||||
|
||||
// private Principal principal;
|
||||
|
||||
public SSOLoginCredential(final String username) {
|
||||
public SsoLoginCredential(final String username) {
|
||||
this.username = username;
|
||||
}
|
||||
|
|
@ -16,12 +16,14 @@
|
|||
package org.codelibs.fess.app.web.sso;
|
||||
|
||||
import org.codelibs.fess.app.web.base.FessLoginAction;
|
||||
import org.codelibs.fess.app.web.base.login.SSOLoginCredential;
|
||||
import org.codelibs.fess.app.web.base.login.EmptyLoginCredential;
|
||||
import org.codelibs.fess.app.web.base.login.LoginCredential;
|
||||
import org.codelibs.fess.app.web.login.LoginAction;
|
||||
import org.jsoup.helper.StringUtil;
|
||||
import org.codelibs.fess.sso.SsoAuthenticator;
|
||||
import org.codelibs.fess.util.ComponentUtil;
|
||||
import org.lastaflute.web.Execute;
|
||||
import org.lastaflute.web.login.exception.LoginFailureException;
|
||||
import org.lastaflute.web.response.HtmlResponse;
|
||||
import org.lastaflute.web.response.ActionResponse;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
|
@ -36,17 +38,20 @@ public class SsoAction extends FessLoginAction {
|
|||
// ==============
|
||||
|
||||
@Execute
|
||||
public HtmlResponse index() {
|
||||
final String user = request.getRemoteUser();
|
||||
if (StringUtil.isBlank(user)) {
|
||||
public ActionResponse index() {
|
||||
final SsoAuthenticator authenticator = ComponentUtil.getSsoAuthenticator();
|
||||
LoginCredential loginCredential = authenticator.getLoginCredential();
|
||||
if (loginCredential == null) {
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("No remote user in SSO request.");
|
||||
logger.debug("No user in SSO request.");
|
||||
}
|
||||
saveError(messages -> messages.addErrorsSsoLoginError(GLOBAL));
|
||||
return redirect(LoginAction.class);
|
||||
} else if (loginCredential instanceof EmptyLoginCredential) {
|
||||
return null;
|
||||
}
|
||||
try {
|
||||
return fessLoginAssist.loginRedirect(new SSOLoginCredential(user), op -> {}, () -> {
|
||||
return fessLoginAssist.loginRedirect(loginCredential, op -> {}, () -> {
|
||||
activityHelper.login(getUserBean());
|
||||
return getHtmlResponse();
|
||||
});
|
||||
|
|
|
@ -0,0 +1,30 @@
|
|||
/*
|
||||
* Copyright 2012-2016 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.exception;
|
||||
|
||||
public class SsoLoginException extends FessSystemException {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
public SsoLoginException(String message) {
|
||||
super(message);
|
||||
}
|
||||
|
||||
public SsoLoginException(String message, Exception e) {
|
||||
super(message, e);
|
||||
}
|
||||
|
||||
}
|
|
@ -1,172 +0,0 @@
|
|||
/*
|
||||
* Copyright 2012-2016 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.filter;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.util.Enumeration;
|
||||
|
||||
import javax.servlet.FilterChain;
|
||||
import javax.servlet.FilterConfig;
|
||||
import javax.servlet.RequestDispatcher;
|
||||
import javax.servlet.ServletContext;
|
||||
import javax.servlet.ServletException;
|
||||
import javax.servlet.ServletRequest;
|
||||
import javax.servlet.ServletResponse;
|
||||
|
||||
import org.codelibs.core.exception.IORuntimeException;
|
||||
import org.codelibs.core.io.ResourceUtil;
|
||||
import org.codelibs.core.lang.StringUtil;
|
||||
import org.codelibs.fess.exception.FessSystemException;
|
||||
import org.codelibs.fess.exception.ServletRuntimeException;
|
||||
import org.codelibs.fess.mylasta.action.FessUserBean;
|
||||
import org.codelibs.fess.util.ComponentUtil;
|
||||
import org.codelibs.spnego.SpnegoHttpFilter;
|
||||
import org.codelibs.spnego.SpnegoHttpServletRequest;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* SpnegoFilter supports Integrated Windows Authentication(SSO).
|
||||
*
|
||||
* @author shinsuke
|
||||
*/
|
||||
public class SpnegoFilter extends SpnegoHttpFilter {
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(SpnegoFilter.class);
|
||||
|
||||
@Override
|
||||
public void init(final FilterConfig filterConfig) throws ServletException {
|
||||
ComponentUtil.processAfterContainerInit(() -> {
|
||||
if (ComponentUtil.getFessConfig().isSsoEnabled()) {
|
||||
initAuthenticator(filterConfig);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void initAuthenticator(final FilterConfig filterConfig) {
|
||||
try {
|
||||
super.init(new FilterConfig() {
|
||||
|
||||
@Override
|
||||
public ServletContext getServletContext() {
|
||||
return filterConfig.getServletContext();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Enumeration<String> getInitParameterNames() {
|
||||
return filterConfig.getInitParameterNames();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getInitParameter(final String name) {
|
||||
if (Constants.KRB5_CONF.equals(name)) {
|
||||
final String krb5Conf = ComponentUtil.getFessConfig().getSpnegoKrb5Conf();
|
||||
if (StringUtil.isNotBlank(krb5Conf)) {
|
||||
final File file = ResourceUtil.getResourceAsFileNoException(krb5Conf);
|
||||
if (file != null) {
|
||||
return file.getAbsolutePath();
|
||||
}
|
||||
}
|
||||
} else if (Constants.LOGIN_CONF.equals(name)) {
|
||||
final String loginConf = ComponentUtil.getFessConfig().getSpnegoLoginConf();
|
||||
final File file = ResourceUtil.getResourceAsFileNoException(loginConf);
|
||||
if (file != null) {
|
||||
return file.getAbsolutePath();
|
||||
}
|
||||
} else if (Constants.PREAUTH_USERNAME.equals(name)) {
|
||||
final String username = ComponentUtil.getFessConfig().getSpnegoPreauthUsername();
|
||||
if (StringUtil.isNotBlank(username)) {
|
||||
return username;
|
||||
}
|
||||
} else if (Constants.PREAUTH_PASSWORD.equals(name)) {
|
||||
final String password = ComponentUtil.getFessConfig().getSpnegoPreauthPassword();
|
||||
if (StringUtil.isNotBlank(password)) {
|
||||
return password;
|
||||
}
|
||||
}
|
||||
return filterConfig.getInitParameter(name);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getFilterName() {
|
||||
return filterConfig.getFilterName();
|
||||
}
|
||||
});
|
||||
} catch (final ServletException e) {
|
||||
throw new FessSystemException("Initialization failed.", e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void doFilter(final ServletRequest request, final ServletResponse response, final FilterChain chain) throws IOException,
|
||||
ServletException {
|
||||
try {
|
||||
ComponentUtil.getRequestManager().findUserBean(FessUserBean.class).ifPresent(u -> {
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("process your request as " + u.getUserId());
|
||||
}
|
||||
doFilter(() -> chain.doFilter(request, response));
|
||||
}).orElse(() -> {
|
||||
if (ComponentUtil.getFessConfig().isSsoEnabled()) {
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("process authentication");
|
||||
}
|
||||
doFilter(() -> SpnegoFilter.super.doFilter(request, response, chain));
|
||||
} else {
|
||||
doFilter(() -> chain.doFilter(request, response));
|
||||
}
|
||||
});
|
||||
} catch (final IORuntimeException e) {
|
||||
throw (IOException) e.getCause();
|
||||
} catch (final ServletRuntimeException e) {
|
||||
throw (ServletException) e.getCause();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void processRequest(final SpnegoHttpServletRequest request, final ServletResponse response, final FilterChain chain)
|
||||
throws IOException, ServletException {
|
||||
if (StringUtil.isNotBlank(request.getRemoteUser())) {
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("log in as " + request.getRemoteUser());
|
||||
}
|
||||
// TODO save path and parameters into session
|
||||
final RequestDispatcher dispatcher = request.getRequestDispatcher(ComponentUtil.getFessConfig().getSsoLoginPath());
|
||||
dispatcher.forward(request, response);
|
||||
} else {
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("this request is not logged in.");
|
||||
}
|
||||
chain.doFilter(request, response);
|
||||
}
|
||||
}
|
||||
|
||||
protected void doFilter(final DoFilterCallback callback) {
|
||||
try {
|
||||
callback.run();
|
||||
} catch (final IOException e) {
|
||||
throw new IORuntimeException(e);
|
||||
} catch (final ServletException e) {
|
||||
throw new ServletRuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
interface DoFilterCallback {
|
||||
|
||||
void run() throws IOException, ServletException;
|
||||
}
|
||||
}
|
|
@ -931,8 +931,8 @@ public interface FessConfig extends FessEnv, org.codelibs.fess.mylasta.direction
|
|||
/** The key of the configuration. e.g. false */
|
||||
String SSO_ENABLED = "sso.enabled";
|
||||
|
||||
/** The key of the configuration. e.g. /sso/ */
|
||||
String SSO_LOGIN_PATH = "sso.login.path";
|
||||
/** The key of the configuration. e.g. 0 */
|
||||
String SPNEGO_LOGGER_LEVEL = "spnego.logger.level";
|
||||
|
||||
/** The key of the configuration. e.g. krb5.conf */
|
||||
String SPNEGO_KRB5_CONF = "spnego.krb5.conf";
|
||||
|
@ -946,6 +946,27 @@ public interface FessConfig extends FessEnv, org.codelibs.fess.mylasta.direction
|
|||
/** The key of the configuration. e.g. password */
|
||||
String SPNEGO_PREAUTH_PASSWORD = "spnego.preauth.password";
|
||||
|
||||
/** The key of the configuration. e.g. spnego-client */
|
||||
String SPNEGO_LOGIN_CLIENT_MODULE = "spnego.login.client.module";
|
||||
|
||||
/** The key of the configuration. e.g. spnego-server */
|
||||
String SPNEGO_LOGIN_SERVER_MODULE = "spnego.login.server.module";
|
||||
|
||||
/** The key of the configuration. e.g. true */
|
||||
String SPNEGO_ALLOW_BASIC = "spnego.allow.basic";
|
||||
|
||||
/** The key of the configuration. e.g. true */
|
||||
String SPNEGO_ALLOW_UNSECURE_BASIC = "spnego.allow.unsecure.basic";
|
||||
|
||||
/** The key of the configuration. e.g. true */
|
||||
String SPNEGO_PROMPT_NTLM = "spnego.prompt.ntlm";
|
||||
|
||||
/** The key of the configuration. e.g. true */
|
||||
String SPNEGO_ALLOW_LOCALHOST = "spnego.allow.localhost";
|
||||
|
||||
/** The key of the configuration. e.g. false */
|
||||
String SPNEGO_ALLOW_DELEGATION = "spnego.allow.delegation";
|
||||
|
||||
/**
|
||||
* Get the value of property as {@link String}.
|
||||
* @param propertyKey The key of the property. (NotNull)
|
||||
|
@ -3757,11 +3778,19 @@ public interface FessConfig extends FessEnv, org.codelibs.fess.mylasta.direction
|
|||
boolean isSsoEnabled();
|
||||
|
||||
/**
|
||||
* Get the value for the key 'sso.login.path'. <br>
|
||||
* The value is, e.g. /sso/ <br>
|
||||
* Get the value for the key 'spnego.logger.level'. <br>
|
||||
* The value is, e.g. 0 <br>
|
||||
* @return The value of found property. (NotNull: if not found, exception but basically no way)
|
||||
*/
|
||||
String getSsoLoginPath();
|
||||
String getSpnegoLoggerLevel();
|
||||
|
||||
/**
|
||||
* Get the value for the key 'spnego.logger.level' as {@link Integer}. <br>
|
||||
* The value is, e.g. 0 <br>
|
||||
* @return The value of found property. (NotNull: if not found, exception but basically no way)
|
||||
* @throws NumberFormatException When the property is not integer.
|
||||
*/
|
||||
Integer getSpnegoLoggerLevelAsInteger();
|
||||
|
||||
/**
|
||||
* Get the value for the key 'spnego.krb5.conf'. <br>
|
||||
|
@ -3791,6 +3820,90 @@ public interface FessConfig extends FessEnv, org.codelibs.fess.mylasta.direction
|
|||
*/
|
||||
String getSpnegoPreauthPassword();
|
||||
|
||||
/**
|
||||
* Get the value for the key 'spnego.login.client.module'. <br>
|
||||
* The value is, e.g. spnego-client <br>
|
||||
* @return The value of found property. (NotNull: if not found, exception but basically no way)
|
||||
*/
|
||||
String getSpnegoLoginClientModule();
|
||||
|
||||
/**
|
||||
* Get the value for the key 'spnego.login.server.module'. <br>
|
||||
* The value is, e.g. spnego-server <br>
|
||||
* @return The value of found property. (NotNull: if not found, exception but basically no way)
|
||||
*/
|
||||
String getSpnegoLoginServerModule();
|
||||
|
||||
/**
|
||||
* Get the value for the key 'spnego.allow.basic'. <br>
|
||||
* The value is, e.g. true <br>
|
||||
* @return The value of found property. (NotNull: if not found, exception but basically no way)
|
||||
*/
|
||||
String getSpnegoAllowBasic();
|
||||
|
||||
/**
|
||||
* Is the property for the key 'spnego.allow.basic' true? <br>
|
||||
* The value is, e.g. true <br>
|
||||
* @return The determination, true or false. (if not found, exception but basically no way)
|
||||
*/
|
||||
boolean isSpnegoAllowBasic();
|
||||
|
||||
/**
|
||||
* Get the value for the key 'spnego.allow.unsecure.basic'. <br>
|
||||
* The value is, e.g. true <br>
|
||||
* @return The value of found property. (NotNull: if not found, exception but basically no way)
|
||||
*/
|
||||
String getSpnegoAllowUnsecureBasic();
|
||||
|
||||
/**
|
||||
* Is the property for the key 'spnego.allow.unsecure.basic' true? <br>
|
||||
* The value is, e.g. true <br>
|
||||
* @return The determination, true or false. (if not found, exception but basically no way)
|
||||
*/
|
||||
boolean isSpnegoAllowUnsecureBasic();
|
||||
|
||||
/**
|
||||
* Get the value for the key 'spnego.prompt.ntlm'. <br>
|
||||
* The value is, e.g. true <br>
|
||||
* @return The value of found property. (NotNull: if not found, exception but basically no way)
|
||||
*/
|
||||
String getSpnegoPromptNtlm();
|
||||
|
||||
/**
|
||||
* Is the property for the key 'spnego.prompt.ntlm' true? <br>
|
||||
* The value is, e.g. true <br>
|
||||
* @return The determination, true or false. (if not found, exception but basically no way)
|
||||
*/
|
||||
boolean isSpnegoPromptNtlm();
|
||||
|
||||
/**
|
||||
* Get the value for the key 'spnego.allow.localhost'. <br>
|
||||
* The value is, e.g. true <br>
|
||||
* @return The value of found property. (NotNull: if not found, exception but basically no way)
|
||||
*/
|
||||
String getSpnegoAllowLocalhost();
|
||||
|
||||
/**
|
||||
* Is the property for the key 'spnego.allow.localhost' true? <br>
|
||||
* The value is, e.g. true <br>
|
||||
* @return The determination, true or false. (if not found, exception but basically no way)
|
||||
*/
|
||||
boolean isSpnegoAllowLocalhost();
|
||||
|
||||
/**
|
||||
* Get the value for the key 'spnego.allow.delegation'. <br>
|
||||
* The value is, e.g. false <br>
|
||||
* @return The value of found property. (NotNull: if not found, exception but basically no way)
|
||||
*/
|
||||
String getSpnegoAllowDelegation();
|
||||
|
||||
/**
|
||||
* Is the property for the key 'spnego.allow.delegation' true? <br>
|
||||
* The value is, e.g. false <br>
|
||||
* @return The determination, true or false. (if not found, exception but basically no way)
|
||||
*/
|
||||
boolean isSpnegoAllowDelegation();
|
||||
|
||||
/**
|
||||
* The simple implementation for configuration.
|
||||
* @author FreeGen
|
||||
|
@ -5280,8 +5393,12 @@ public interface FessConfig extends FessEnv, org.codelibs.fess.mylasta.direction
|
|||
return is(FessConfig.SSO_ENABLED);
|
||||
}
|
||||
|
||||
public String getSsoLoginPath() {
|
||||
return get(FessConfig.SSO_LOGIN_PATH);
|
||||
public String getSpnegoLoggerLevel() {
|
||||
return get(FessConfig.SPNEGO_LOGGER_LEVEL);
|
||||
}
|
||||
|
||||
public Integer getSpnegoLoggerLevelAsInteger() {
|
||||
return getAsInteger(FessConfig.SPNEGO_LOGGER_LEVEL);
|
||||
}
|
||||
|
||||
public String getSpnegoKrb5Conf() {
|
||||
|
@ -5299,5 +5416,53 @@ public interface FessConfig extends FessEnv, org.codelibs.fess.mylasta.direction
|
|||
public String getSpnegoPreauthPassword() {
|
||||
return get(FessConfig.SPNEGO_PREAUTH_PASSWORD);
|
||||
}
|
||||
|
||||
public String getSpnegoLoginClientModule() {
|
||||
return get(FessConfig.SPNEGO_LOGIN_CLIENT_MODULE);
|
||||
}
|
||||
|
||||
public String getSpnegoLoginServerModule() {
|
||||
return get(FessConfig.SPNEGO_LOGIN_SERVER_MODULE);
|
||||
}
|
||||
|
||||
public String getSpnegoAllowBasic() {
|
||||
return get(FessConfig.SPNEGO_ALLOW_BASIC);
|
||||
}
|
||||
|
||||
public boolean isSpnegoAllowBasic() {
|
||||
return is(FessConfig.SPNEGO_ALLOW_BASIC);
|
||||
}
|
||||
|
||||
public String getSpnegoAllowUnsecureBasic() {
|
||||
return get(FessConfig.SPNEGO_ALLOW_UNSECURE_BASIC);
|
||||
}
|
||||
|
||||
public boolean isSpnegoAllowUnsecureBasic() {
|
||||
return is(FessConfig.SPNEGO_ALLOW_UNSECURE_BASIC);
|
||||
}
|
||||
|
||||
public String getSpnegoPromptNtlm() {
|
||||
return get(FessConfig.SPNEGO_PROMPT_NTLM);
|
||||
}
|
||||
|
||||
public boolean isSpnegoPromptNtlm() {
|
||||
return is(FessConfig.SPNEGO_PROMPT_NTLM);
|
||||
}
|
||||
|
||||
public String getSpnegoAllowLocalhost() {
|
||||
return get(FessConfig.SPNEGO_ALLOW_LOCALHOST);
|
||||
}
|
||||
|
||||
public boolean isSpnegoAllowLocalhost() {
|
||||
return is(FessConfig.SPNEGO_ALLOW_LOCALHOST);
|
||||
}
|
||||
|
||||
public String getSpnegoAllowDelegation() {
|
||||
return get(FessConfig.SPNEGO_ALLOW_DELEGATION);
|
||||
}
|
||||
|
||||
public boolean isSpnegoAllowDelegation() {
|
||||
return is(FessConfig.SPNEGO_ALLOW_DELEGATION);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
24
src/main/java/org/codelibs/fess/sso/SsoAuthenticator.java
Normal file
24
src/main/java/org/codelibs/fess/sso/SsoAuthenticator.java
Normal file
|
@ -0,0 +1,24 @@
|
|||
/*
|
||||
* Copyright 2012-2016 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;
|
||||
|
||||
import org.codelibs.fess.app.web.base.login.LoginCredential;
|
||||
|
||||
public interface SsoAuthenticator {
|
||||
|
||||
LoginCredential getLoginCredential();
|
||||
|
||||
}
|
|
@ -0,0 +1,162 @@
|
|||
/*
|
||||
* Copyright 2012-2016 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.util.Enumeration;
|
||||
|
||||
import javax.annotation.PostConstruct;
|
||||
import javax.servlet.FilterConfig;
|
||||
import javax.servlet.ServletContext;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
import org.codelibs.core.lang.StringUtil;
|
||||
import org.codelibs.fess.app.web.base.login.EmptyLoginCredential;
|
||||
import org.codelibs.fess.app.web.base.login.LoginCredential;
|
||||
import org.codelibs.fess.app.web.base.login.SsoLoginCredential;
|
||||
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.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 (ComponentUtil.getFessConfig().isSsoEnabled()) {
|
||||
try {
|
||||
// set some System properties
|
||||
final SpnegoFilterConfig config = SpnegoFilterConfig.getInstance(new SpengoConfig());
|
||||
|
||||
// pre-authenticate
|
||||
authenticator = new org.codelibs.spnego.SpnegoAuthenticator(config);
|
||||
} catch (Exception e) {
|
||||
throw new FessSystemException("Failed to initialize SPNEGO.", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.codelibs.fess.sso.spnego.SsoAuthenticator#getLoginCredential()
|
||||
*/
|
||||
@Override
|
||||
public LoginCredential getLoginCredential() {
|
||||
if (!ComponentUtil.getFessConfig().isSsoEnabled()) {
|
||||
return null;
|
||||
}
|
||||
|
||||
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 (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 EmptyLoginCredential();
|
||||
}
|
||||
|
||||
// assert
|
||||
if (null == principal) {
|
||||
String msg = "Principal was null.";
|
||||
logger.error(msg);
|
||||
throw new SsoLoginException(msg);
|
||||
}
|
||||
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("principal=" + principal);
|
||||
}
|
||||
|
||||
final String username = LaRequestUtil.getOptionalRequest().map(r -> r.getRemoteUser()).orElseGet(() -> null);
|
||||
if (StringUtil.isBlank(username)) {
|
||||
return null;
|
||||
}
|
||||
return new SsoLoginCredential(username);
|
||||
}).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(String name) {
|
||||
if (SpnegoHttpFilter.Constants.LOGGER_LEVEL.equals(name)) {
|
||||
return fessConfig.getSpnegoLoggerLevel();
|
||||
} else if (SpnegoHttpFilter.Constants.LOGIN_CONF.equals(name)) {
|
||||
return fessConfig.getSpnegoLoginConf();
|
||||
} else if (SpnegoHttpFilter.Constants.KRB5_CONF.equals(name)) {
|
||||
return 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;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Enumeration<String> getInitParameterNames() {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
}
|
||||
}
|
|
@ -59,6 +59,7 @@ import org.codelibs.fess.indexer.IndexUpdater;
|
|||
import org.codelibs.fess.job.JobExecutor;
|
||||
import org.codelibs.fess.ldap.LdapManager;
|
||||
import org.codelibs.fess.mylasta.direction.FessConfig;
|
||||
import org.codelibs.fess.sso.SsoAuthenticator;
|
||||
import org.lastaflute.core.message.MessageManager;
|
||||
import org.lastaflute.di.core.SingletonLaContainer;
|
||||
import org.lastaflute.di.core.factory.SingletonLaContainerFactory;
|
||||
|
@ -69,8 +70,11 @@ import org.slf4j.Logger;
|
|||
import org.slf4j.LoggerFactory;
|
||||
|
||||
public final class ComponentUtil {
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(ComponentUtil.class);
|
||||
|
||||
private static final String SSO_AUTHENTICATOR = "ssoAuthenticator";
|
||||
|
||||
private static final String PERMISSION_HELPER = "permissionHelper";
|
||||
|
||||
private static final String QUERY_PARSER = "queryParser";
|
||||
|
@ -356,6 +360,10 @@ public final class ComponentUtil {
|
|||
return getComponent(PERMISSION_HELPER);
|
||||
}
|
||||
|
||||
public static SsoAuthenticator getSsoAuthenticator() {
|
||||
return getComponent(SSO_AUTHENTICATOR);
|
||||
}
|
||||
|
||||
public static CrawlerClientFactory getCrawlerClientFactory() {
|
||||
return getComponent(CrawlerClientFactory.class);
|
||||
}
|
||||
|
|
|
@ -12,6 +12,7 @@
|
|||
<include path="fess_dict.xml"/>
|
||||
<include path="fess_job.xml"/>
|
||||
<include path="fess_screenshot.xml"/>
|
||||
<include path="fess_sso.xml"/>
|
||||
|
||||
<include path="crawler/client.xml" />
|
||||
<include path="crawler/mimetype.xml" />
|
||||
|
|
|
@ -473,9 +473,17 @@ ldap.attr.homeDirectory=homeDirectory
|
|||
# SSO
|
||||
# ------
|
||||
sso.enabled=false
|
||||
sso.login.path=/sso/
|
||||
spnego.logger.level=0
|
||||
spnego.krb5.conf=krb5.conf
|
||||
spnego.login.conf=auth_login.conf
|
||||
spnego.preauth.username=username
|
||||
spnego.preauth.password=password
|
||||
spnego.login.client.module=spnego-client
|
||||
spnego.login.server.module=spnego-server
|
||||
spnego.allow.basic=true
|
||||
spnego.allow.unsecure.basic=true
|
||||
spnego.prompt.ntlm=true
|
||||
spnego.allow.localhost=true
|
||||
spnego.allow.delegation=false
|
||||
|
||||
|
||||
|
|
8
src/main/resources/fess_sso.xml
Normal file
8
src/main/resources/fess_sso.xml
Normal file
|
@ -0,0 +1,8 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE components PUBLIC "-//DBFLUTE//DTD LastaDi 1.0//EN"
|
||||
"http://dbflute.org/meta/lastadi10.dtd">
|
||||
<components>
|
||||
<component name="ssoAuthenticator" class="org.codelibs.fess.sso.spnego.SpnegoAuthenticator">
|
||||
</component>
|
||||
|
||||
</components>
|
|
@ -55,39 +55,6 @@
|
|||
<filter-class>org.lastaflute.web.servlet.filter.LastaToActionFilter</filter-class>
|
||||
</filter>
|
||||
|
||||
<filter>
|
||||
<filter-name>spnegoFilter</filter-name>
|
||||
<filter-class>org.codelibs.fess.filter.SpnegoFilter</filter-class>
|
||||
<init-param>
|
||||
<param-name>spnego.allow.basic</param-name>
|
||||
<param-value>true</param-value>
|
||||
</init-param>
|
||||
<init-param>
|
||||
<param-name>spnego.allow.localhost</param-name>
|
||||
<param-value>true</param-value>
|
||||
</init-param>
|
||||
<init-param>
|
||||
<param-name>spnego.allow.unsecure.basic</param-name>
|
||||
<param-value>true</param-value>
|
||||
</init-param>
|
||||
<init-param>
|
||||
<param-name>spnego.login.client.module</param-name>
|
||||
<param-value>spnego-client</param-value>
|
||||
</init-param>
|
||||
<init-param>
|
||||
<param-name>spnego.login.server.module</param-name>
|
||||
<param-value>spnego-server</param-value>
|
||||
</init-param>
|
||||
<init-param>
|
||||
<param-name>spnego.prompt.ntlm</param-name>
|
||||
<param-value>true</param-value>
|
||||
</init-param>
|
||||
<init-param>
|
||||
<param-name>spnego.logger.level</param-name>
|
||||
<param-value>0</param-value>
|
||||
</init-param>
|
||||
</filter>
|
||||
|
||||
<!-- ================================================================================= -->
|
||||
<!-- Filter Mapping -->
|
||||
<!-- ============== -->
|
||||
|
@ -106,12 +73,6 @@
|
|||
<dispatcher>INCLUDE</dispatcher>
|
||||
</filter-mapping>
|
||||
|
||||
<filter-mapping>
|
||||
<filter-name>spnegoFilter</filter-name>
|
||||
<url-pattern>/*</url-pattern>
|
||||
<dispatcher>REQUEST</dispatcher>
|
||||
</filter-mapping>
|
||||
|
||||
<filter-mapping>
|
||||
<filter-name>webApiFilter</filter-name>
|
||||
<url-pattern>/*</url-pattern>
|
||||
|
|
Loading…
Add table
Reference in a new issue