#1633 azure ad support
This commit is contained in:
parent
7d0c262849
commit
947786fcb8
20 changed files with 706 additions and 552 deletions
15
pom.xml
15
pom.xml
|
@ -1332,6 +1332,21 @@
|
|||
</exclusion>
|
||||
</exclusions>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.microsoft.azure</groupId>
|
||||
<artifactId>adal4j</artifactId>
|
||||
<version>1.6.3</version>
|
||||
<exclusions>
|
||||
<exclusion>
|
||||
<groupId>com.github.stephenc.jcip</groupId>
|
||||
<artifactId>jcip-annotations</artifactId>
|
||||
</exclusion>
|
||||
<exclusion>
|
||||
<groupId>com.sun.mail</groupId>
|
||||
<artifactId>javax.mail</artifactId>
|
||||
</exclusion>
|
||||
</exclusions>
|
||||
</dependency>
|
||||
|
||||
<!-- suggest library -->
|
||||
<dependency>
|
||||
|
|
|
@ -0,0 +1,103 @@
|
|||
/*
|
||||
* Copyright 2012-2019 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 static org.codelibs.core.stream.StreamUtil.stream;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
import org.codelibs.fess.entity.FessUser;
|
||||
import org.codelibs.fess.helper.SystemHelper;
|
||||
import org.codelibs.fess.util.ComponentUtil;
|
||||
import org.lastaflute.web.login.credential.LoginCredential;
|
||||
|
||||
import com.microsoft.aad.adal4j.AuthenticationResult;
|
||||
|
||||
public class AzureAdCredential implements LoginCredential, FessCredential {
|
||||
|
||||
private final AuthenticationResult authResult;
|
||||
|
||||
public AzureAdCredential(final AuthenticationResult authResult) {
|
||||
this.authResult = authResult;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getUserId() {
|
||||
return authResult.getUserInfo().getDisplayableId();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "{" + authResult.getUserInfo().getDisplayableId() + "}";
|
||||
}
|
||||
|
||||
public User getUser() {
|
||||
return new User(authResult.getUserInfo().getDisplayableId(), new String[0], new String[0]);
|
||||
}
|
||||
|
||||
public static class User implements FessUser {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
protected final String name;
|
||||
|
||||
protected String[] groups;
|
||||
|
||||
protected String[] roles;
|
||||
|
||||
protected String[] permissions;
|
||||
|
||||
protected User(final String name, final String[] groups, final String[] roles) {
|
||||
this.name = name;
|
||||
this.groups = groups;
|
||||
this.roles = roles;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String[] getRoleNames() {
|
||||
return roles;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String[] getGroupNames() {
|
||||
return groups;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String[] getPermissions() {
|
||||
if (permissions == null) {
|
||||
final SystemHelper systemHelper = ComponentUtil.getSystemHelper();
|
||||
final Set<String> permissionSet = new HashSet<>();
|
||||
permissionSet.add(systemHelper.getSearchRoleByUser(name));
|
||||
stream(groups).of(stream -> stream.forEach(s -> permissionSet.add(systemHelper.getSearchRoleByGroup(s))));
|
||||
stream(roles).of(stream -> stream.forEach(s -> permissionSet.add(systemHelper.getSearchRoleByRole(s))));
|
||||
permissions = permissionSet.toArray(new String[permissionSet.size()]);
|
||||
}
|
||||
return permissions;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEditable() {
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
|
@ -0,0 +1,22 @@
|
|||
/*
|
||||
* Copyright 2012-2019 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;
|
||||
|
||||
public interface FessCredential {
|
||||
|
||||
String getUserId();
|
||||
|
||||
}
|
|
@ -15,6 +15,8 @@
|
|||
*/
|
||||
package org.codelibs.fess.app.web.base.login;
|
||||
|
||||
import java.util.function.Function;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
|
||||
import org.codelibs.fess.Constants;
|
||||
|
@ -25,6 +27,7 @@ import org.codelibs.fess.es.user.exbhv.UserBhv;
|
|||
import org.codelibs.fess.exception.UserRoleLoginException;
|
||||
import org.codelibs.fess.mylasta.action.FessUserBean;
|
||||
import org.codelibs.fess.mylasta.direction.FessConfig;
|
||||
import org.codelibs.fess.sso.SsoAuthenticator;
|
||||
import org.codelibs.fess.util.ComponentUtil;
|
||||
import org.dbflute.optional.OptionalEntity;
|
||||
import org.dbflute.optional.OptionalThing;
|
||||
|
@ -34,7 +37,6 @@ import org.lastaflute.web.login.LoginHandlingResource;
|
|||
import org.lastaflute.web.login.PrimaryLoginManager;
|
||||
import org.lastaflute.web.login.TypicalLoginAssist;
|
||||
import org.lastaflute.web.login.credential.LoginCredential;
|
||||
import org.lastaflute.web.login.credential.UserPasswordCredential;
|
||||
import org.lastaflute.web.login.exception.LoginRequiredException;
|
||||
import org.lastaflute.web.login.option.LoginSpecifiedOption;
|
||||
import org.lastaflute.web.servlet.session.SessionManager;
|
||||
|
@ -140,8 +142,8 @@ public class FessLoginAssist extends TypicalLoginAssist<String, FessUserBean, Fe
|
|||
|
||||
@Override
|
||||
protected void resolveCredential(final CredentialResolver resolver) {
|
||||
resolver.resolve(UserPasswordCredential.class, credential -> {
|
||||
final UserPasswordCredential userCredential = credential;
|
||||
resolver.resolve(LocalUserCredential.class, credential -> {
|
||||
final LocalUserCredential userCredential = credential;
|
||||
final String username = userCredential.getUser();
|
||||
final String password = userCredential.getPassword();
|
||||
if (!fessConfig.isAdminUser(username)) {
|
||||
|
@ -152,16 +154,23 @@ public class FessLoginAssist extends TypicalLoginAssist<String, FessUserBean, Fe
|
|||
}
|
||||
return doFindLoginUser(username, encryptPassword(password));
|
||||
});
|
||||
resolver.resolve(SpnegoCredential.class, credential -> {
|
||||
final String username = credential.getUsername();
|
||||
if (!fessConfig.isAdminUser(username)) {
|
||||
return ComponentUtil.getLdapManager().login(username);
|
||||
}
|
||||
return OptionalEntity.empty();
|
||||
});
|
||||
resolver.resolve(OpenIdConnectCredential.class, credential -> {
|
||||
return OptionalEntity.of(credential.getUser());
|
||||
});
|
||||
final LoginCredentialResolver loginResolver = new LoginCredentialResolver(resolver);
|
||||
for (final SsoAuthenticator auth : ComponentUtil.getSsoManager().getAuthenticators()) {
|
||||
auth.resolveCredential(loginResolver);
|
||||
}
|
||||
}
|
||||
|
||||
public static class LoginCredentialResolver {
|
||||
private final TypicalLoginAssist<String, FessUserBean, FessUser>.CredentialResolver resolver;
|
||||
|
||||
public LoginCredentialResolver(final CredentialResolver resolver) {
|
||||
this.resolver = resolver;
|
||||
}
|
||||
|
||||
public <CREDENTIAL extends LoginCredential> void resolve(final Class<CREDENTIAL> credentialType,
|
||||
final Function<CREDENTIAL, OptionalEntity<FessUser>> oneArgLambda) {
|
||||
resolver.resolve(credentialType, credential -> oneArgLambda.apply(credential));
|
||||
}
|
||||
}
|
||||
|
||||
protected OptionalEntity<FessUser> doFindLoginUser(final String username, final String cipheredPassword) {
|
||||
|
|
|
@ -0,0 +1,29 @@
|
|||
/*
|
||||
* Copyright 2012-2019 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 org.lastaflute.web.login.credential.UserPasswordCredential;
|
||||
|
||||
public class LocalUserCredential extends UserPasswordCredential implements FessCredential {
|
||||
public LocalUserCredential(String user, String password) {
|
||||
super(user, password);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getUserId() {
|
||||
return getUser();
|
||||
}
|
||||
}
|
|
@ -27,7 +27,7 @@ import org.codelibs.fess.mylasta.direction.FessConfig;
|
|||
import org.codelibs.fess.util.ComponentUtil;
|
||||
import org.lastaflute.web.login.credential.LoginCredential;
|
||||
|
||||
public class OpenIdConnectCredential implements LoginCredential {
|
||||
public class OpenIdConnectCredential implements LoginCredential, FessCredential {
|
||||
|
||||
private final Map<String, Object> attributes;
|
||||
|
||||
|
@ -37,16 +37,17 @@ public class OpenIdConnectCredential implements LoginCredential {
|
|||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "{" + getEmail() + "}";
|
||||
return "{" + getUserId() + "}";
|
||||
}
|
||||
|
||||
public String getEmail() {
|
||||
@Override
|
||||
public String getUserId() {
|
||||
return (String) attributes.get("email");
|
||||
}
|
||||
|
||||
public User getUser() {
|
||||
final FessConfig fessConfig = ComponentUtil.getFessConfig();
|
||||
return new User(getEmail(), fessConfig.getOicDefaultGroupsAsArray(), fessConfig.getOicDefaultRolesAsArray());
|
||||
return new User(getUserId(), fessConfig.getOicDefaultGroupsAsArray(), fessConfig.getOicDefaultRolesAsArray());
|
||||
}
|
||||
|
||||
public static class User implements FessUser {
|
||||
|
|
|
@ -17,21 +17,21 @@ package org.codelibs.fess.app.web.base.login;
|
|||
|
||||
import org.lastaflute.web.login.credential.LoginCredential;
|
||||
|
||||
public class SpnegoCredential implements LoginCredential {
|
||||
public class SpnegoCredential implements LoginCredential, FessCredential {
|
||||
private final String username;
|
||||
|
||||
// private Principal principal;
|
||||
|
||||
public SpnegoCredential(final String username) {
|
||||
this.username = username;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getUserId() {
|
||||
return username;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "{" + username + "}";
|
||||
}
|
||||
|
||||
public String getUsername() {
|
||||
return username;
|
||||
}
|
||||
}
|
|
@ -16,10 +16,10 @@
|
|||
package org.codelibs.fess.app.web.login;
|
||||
|
||||
import org.codelibs.fess.app.web.base.FessLoginAction;
|
||||
import org.codelibs.fess.app.web.base.login.LocalUserCredential;
|
||||
import org.codelibs.fess.util.RenderDataUtil;
|
||||
import org.dbflute.optional.OptionalThing;
|
||||
import org.lastaflute.web.Execute;
|
||||
import org.lastaflute.web.login.credential.UserPasswordCredential;
|
||||
import org.lastaflute.web.login.exception.LoginFailureException;
|
||||
import org.lastaflute.web.response.HtmlResponse;
|
||||
|
||||
|
@ -52,13 +52,13 @@ public class LoginAction extends FessLoginAction {
|
|||
final String password = form.password;
|
||||
form.clearSecurityInfo();
|
||||
try {
|
||||
return fessLoginAssist.loginRedirect(new UserPasswordCredential(username, password), op -> {}, () -> {
|
||||
return fessLoginAssist.loginRedirect(new LocalUserCredential(username, password), op -> {}, () -> {
|
||||
activityHelper.login(getUserBean());
|
||||
userInfoHelper.deleteUserCodeFromCookie(request);
|
||||
return getHtmlResponse();
|
||||
});
|
||||
} catch (final LoginFailureException lfe) {
|
||||
activityHelper.loginFailure(OptionalThing.of(new UserPasswordCredential(username, password)));
|
||||
activityHelper.loginFailure(OptionalThing.of(new LocalUserCredential(username, password)));
|
||||
throwValidationError(messages -> messages.addErrorsLoginError(GLOBAL), () -> asIndexPage(form));
|
||||
}
|
||||
return redirect(getClass());
|
||||
|
|
|
@ -23,9 +23,9 @@ import javax.annotation.Resource;
|
|||
|
||||
import org.codelibs.fess.app.service.UserService;
|
||||
import org.codelibs.fess.app.web.base.FessSearchAction;
|
||||
import org.codelibs.fess.app.web.base.login.LocalUserCredential;
|
||||
import org.codelibs.fess.app.web.login.LoginAction;
|
||||
import org.lastaflute.web.Execute;
|
||||
import org.lastaflute.web.login.credential.UserPasswordCredential;
|
||||
import org.lastaflute.web.response.HtmlResponse;
|
||||
import org.lastaflute.web.validation.VaErrorHook;
|
||||
import org.slf4j.Logger;
|
||||
|
@ -87,7 +87,7 @@ public class ProfileAction extends FessSearchAction {
|
|||
}, validationErrorLambda);
|
||||
}
|
||||
|
||||
fessLoginAssist.findLoginUser(new UserPasswordCredential(getUserBean().get().getUserId(), form.oldPassword)).orElseGet(() -> {
|
||||
fessLoginAssist.findLoginUser(new LocalUserCredential(getUserBean().get().getUserId(), form.oldPassword)).orElseGet(() -> {
|
||||
throwValidationError(messages -> {
|
||||
messages.addErrorsNoUserForChangingPassword(GLOBAL);
|
||||
}, validationErrorLambda);
|
||||
|
|
|
@ -24,13 +24,11 @@ import java.util.stream.Collectors;
|
|||
import javax.annotation.PostConstruct;
|
||||
|
||||
import org.codelibs.core.lang.StringUtil;
|
||||
import org.codelibs.fess.app.web.base.login.OpenIdConnectCredential;
|
||||
import org.codelibs.fess.app.web.base.login.SpnegoCredential;
|
||||
import org.codelibs.fess.app.web.base.login.FessCredential;
|
||||
import org.codelibs.fess.mylasta.action.FessUserBean;
|
||||
import org.codelibs.fess.util.ComponentUtil;
|
||||
import org.dbflute.optional.OptionalThing;
|
||||
import org.lastaflute.web.login.credential.LoginCredential;
|
||||
import org.lastaflute.web.login.credential.UserPasswordCredential;
|
||||
import org.lastaflute.web.util.LaRequestUtil;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
@ -74,18 +72,10 @@ public class ActivityHelper {
|
|||
buffer.append('\t');
|
||||
buffer.append("class:");
|
||||
buffer.append(c.getClass().getSimpleName());
|
||||
if (c instanceof OpenIdConnectCredential) {
|
||||
if (c instanceof FessCredential) {
|
||||
buffer.append('\t');
|
||||
buffer.append("user:");
|
||||
buffer.append(((OpenIdConnectCredential) c).getEmail());
|
||||
} else if (c instanceof SpnegoCredential) {
|
||||
buffer.append('\t');
|
||||
buffer.append("user:");
|
||||
buffer.append(((SpnegoCredential) c).getUsername());
|
||||
} else if (c instanceof UserPasswordCredential) {
|
||||
buffer.append('\t');
|
||||
buffer.append("user:");
|
||||
buffer.append(((UserPasswordCredential) c).getUser());
|
||||
buffer.append(((FessCredential) c).getUserId());
|
||||
}
|
||||
return buffer.toString();
|
||||
}).ifPresent(buf::append);
|
||||
|
|
|
@ -1397,72 +1397,6 @@ public interface FessConfig extends FessEnv, org.codelibs.fess.mylasta.direction
|
|||
/** The key of the configuration. e.g. homeDirectory */
|
||||
String LDAP_ATTR_HOME_DIRECTORY = "ldap.attr.homeDirectory";
|
||||
|
||||
/** The key of the configuration. e.g. none */
|
||||
String SSO_TYPE = "sso.type";
|
||||
|
||||
/** The key of the configuration. e.g. */
|
||||
String SPNEGO_LOGGER_LEVEL = "spnego.logger.level";
|
||||
|
||||
/** The key of the configuration. e.g. krb5.conf */
|
||||
String SPNEGO_KRB5_CONF = "spnego.krb5.conf";
|
||||
|
||||
/** The key of the configuration. e.g. auth_login.conf */
|
||||
String SPNEGO_LOGIN_CONF = "spnego.login.conf";
|
||||
|
||||
/** The key of the configuration. e.g. username */
|
||||
String SPNEGO_PREAUTH_USERNAME = "spnego.preauth.username";
|
||||
|
||||
/** 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";
|
||||
|
||||
/** The key of the configuration. e.g. */
|
||||
String SPNEGO_EXCLUDE_DIRS = "spnego.exclude.dirs";
|
||||
|
||||
/** The key of the configuration. e.g. __CLIENT_ID__ */
|
||||
String OIC_CLIENT_ID = "oic.client.id";
|
||||
|
||||
/** The key of the configuration. e.g. __CLIENT_SECRET__ */
|
||||
String OIC_CLIENT_SECRET = "oic.client.secret";
|
||||
|
||||
/** The key of the configuration. e.g. https://accounts.google.com/o/oauth2/auth */
|
||||
String OIC_AUTH_SERVER_URL = "oic.auth.server.url";
|
||||
|
||||
/** The key of the configuration. e.g. http://localhost:8080/sso/ */
|
||||
String OIC_REDIRECT_URL = "oic.redirect.url";
|
||||
|
||||
/** The key of the configuration. e.g. openid email */
|
||||
String OIC_SCOPE = "oic.scope";
|
||||
|
||||
/** The key of the configuration. e.g. https://accounts.google.com/o/oauth2/token */
|
||||
String OIC_TOKEN_SERVER_URL = "oic.token.server.url";
|
||||
|
||||
/** The key of the configuration. e.g. guest */
|
||||
String OIC_DEFAULT_ROLES = "oic.default.roles";
|
||||
|
||||
/** The key of the configuration. e.g. */
|
||||
String OIC_DEFAULT_GROUPS = "oic.default.groups";
|
||||
|
||||
/**
|
||||
* Get the value of property as {@link String}.
|
||||
* @param propertyKey The key of the property. (NotNull)
|
||||
|
@ -5908,220 +5842,6 @@ public interface FessConfig extends FessEnv, org.codelibs.fess.mylasta.direction
|
|||
*/
|
||||
String getLdapAttrHomeDirectory();
|
||||
|
||||
/**
|
||||
* Get the value for the key 'sso.type'. <br>
|
||||
* The value is, e.g. none <br>
|
||||
* comment: ------
|
||||
* @return The value of found property. (NotNull: if not found, exception but basically no way)
|
||||
*/
|
||||
String getSsoType();
|
||||
|
||||
/**
|
||||
* Get the value for the key 'spnego.logger.level'. <br>
|
||||
* The value is, e.g. <br>
|
||||
* @return The value of found property. (NotNull: if not found, exception but basically no way)
|
||||
*/
|
||||
String getSpnegoLoggerLevel();
|
||||
|
||||
/**
|
||||
* Get the value for the key 'spnego.logger.level' as {@link Integer}. <br>
|
||||
* The value is, e.g. <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>
|
||||
* The value is, e.g. krb5.conf <br>
|
||||
* @return The value of found property. (NotNull: if not found, exception but basically no way)
|
||||
*/
|
||||
String getSpnegoKrb5Conf();
|
||||
|
||||
/**
|
||||
* Get the value for the key 'spnego.login.conf'. <br>
|
||||
* The value is, e.g. auth_login.conf <br>
|
||||
* @return The value of found property. (NotNull: if not found, exception but basically no way)
|
||||
*/
|
||||
String getSpnegoLoginConf();
|
||||
|
||||
/**
|
||||
* Get the value for the key 'spnego.preauth.username'. <br>
|
||||
* The value is, e.g. username <br>
|
||||
* @return The value of found property. (NotNull: if not found, exception but basically no way)
|
||||
*/
|
||||
String getSpnegoPreauthUsername();
|
||||
|
||||
/**
|
||||
* Get the value for the key 'spnego.preauth.password'. <br>
|
||||
* The value is, e.g. password <br>
|
||||
* @return The value of found property. (NotNull: if not found, exception but basically no way)
|
||||
*/
|
||||
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();
|
||||
|
||||
/**
|
||||
* Get the value for the key 'spnego.exclude.dirs'. <br>
|
||||
* The value is, e.g. <br>
|
||||
* @return The value of found property. (NotNull: if not found, exception but basically no way)
|
||||
*/
|
||||
String getSpnegoExcludeDirs();
|
||||
|
||||
/**
|
||||
* Get the value for the key 'spnego.exclude.dirs' as {@link Integer}. <br>
|
||||
* The value is, e.g. <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 getSpnegoExcludeDirsAsInteger();
|
||||
|
||||
/**
|
||||
* Get the value for the key 'oic.client.id'. <br>
|
||||
* The value is, e.g. __CLIENT_ID__ <br>
|
||||
* @return The value of found property. (NotNull: if not found, exception but basically no way)
|
||||
*/
|
||||
String getOicClientId();
|
||||
|
||||
/**
|
||||
* Get the value for the key 'oic.client.secret'. <br>
|
||||
* The value is, e.g. __CLIENT_SECRET__ <br>
|
||||
* @return The value of found property. (NotNull: if not found, exception but basically no way)
|
||||
*/
|
||||
String getOicClientSecret();
|
||||
|
||||
/**
|
||||
* Get the value for the key 'oic.auth.server.url'. <br>
|
||||
* The value is, e.g. https://accounts.google.com/o/oauth2/auth <br>
|
||||
* @return The value of found property. (NotNull: if not found, exception but basically no way)
|
||||
*/
|
||||
String getOicAuthServerUrl();
|
||||
|
||||
/**
|
||||
* Get the value for the key 'oic.redirect.url'. <br>
|
||||
* The value is, e.g. http://localhost:8080/sso/ <br>
|
||||
* @return The value of found property. (NotNull: if not found, exception but basically no way)
|
||||
*/
|
||||
String getOicRedirectUrl();
|
||||
|
||||
/**
|
||||
* Get the value for the key 'oic.scope'. <br>
|
||||
* The value is, e.g. openid email <br>
|
||||
* @return The value of found property. (NotNull: if not found, exception but basically no way)
|
||||
*/
|
||||
String getOicScope();
|
||||
|
||||
/**
|
||||
* Get the value for the key 'oic.token.server.url'. <br>
|
||||
* The value is, e.g. https://accounts.google.com/o/oauth2/token <br>
|
||||
* @return The value of found property. (NotNull: if not found, exception but basically no way)
|
||||
*/
|
||||
String getOicTokenServerUrl();
|
||||
|
||||
/**
|
||||
* Get the value for the key 'oic.default.roles'. <br>
|
||||
* The value is, e.g. guest <br>
|
||||
* @return The value of found property. (NotNull: if not found, exception but basically no way)
|
||||
*/
|
||||
String getOicDefaultRoles();
|
||||
|
||||
/**
|
||||
* Get the value for the key 'oic.default.groups'. <br>
|
||||
* The value is, e.g. <br>
|
||||
* @return The value of found property. (NotNull: if not found, exception but basically no way)
|
||||
*/
|
||||
String getOicDefaultGroups();
|
||||
|
||||
/**
|
||||
* Get the value for the key 'oic.default.groups' as {@link Integer}. <br>
|
||||
* The value is, e.g. <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 getOicDefaultGroupsAsInteger();
|
||||
|
||||
/**
|
||||
* The simple implementation for configuration.
|
||||
* @author FreeGen
|
||||
|
@ -8467,126 +8187,6 @@ public interface FessConfig extends FessEnv, org.codelibs.fess.mylasta.direction
|
|||
return get(FessConfig.LDAP_ATTR_HOME_DIRECTORY);
|
||||
}
|
||||
|
||||
public String getSsoType() {
|
||||
return get(FessConfig.SSO_TYPE);
|
||||
}
|
||||
|
||||
public String getSpnegoLoggerLevel() {
|
||||
return get(FessConfig.SPNEGO_LOGGER_LEVEL);
|
||||
}
|
||||
|
||||
public Integer getSpnegoLoggerLevelAsInteger() {
|
||||
return getAsInteger(FessConfig.SPNEGO_LOGGER_LEVEL);
|
||||
}
|
||||
|
||||
public String getSpnegoKrb5Conf() {
|
||||
return get(FessConfig.SPNEGO_KRB5_CONF);
|
||||
}
|
||||
|
||||
public String getSpnegoLoginConf() {
|
||||
return get(FessConfig.SPNEGO_LOGIN_CONF);
|
||||
}
|
||||
|
||||
public String getSpnegoPreauthUsername() {
|
||||
return get(FessConfig.SPNEGO_PREAUTH_USERNAME);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
public String getSpnegoExcludeDirs() {
|
||||
return get(FessConfig.SPNEGO_EXCLUDE_DIRS);
|
||||
}
|
||||
|
||||
public Integer getSpnegoExcludeDirsAsInteger() {
|
||||
return getAsInteger(FessConfig.SPNEGO_EXCLUDE_DIRS);
|
||||
}
|
||||
|
||||
public String getOicClientId() {
|
||||
return get(FessConfig.OIC_CLIENT_ID);
|
||||
}
|
||||
|
||||
public String getOicClientSecret() {
|
||||
return get(FessConfig.OIC_CLIENT_SECRET);
|
||||
}
|
||||
|
||||
public String getOicAuthServerUrl() {
|
||||
return get(FessConfig.OIC_AUTH_SERVER_URL);
|
||||
}
|
||||
|
||||
public String getOicRedirectUrl() {
|
||||
return get(FessConfig.OIC_REDIRECT_URL);
|
||||
}
|
||||
|
||||
public String getOicScope() {
|
||||
return get(FessConfig.OIC_SCOPE);
|
||||
}
|
||||
|
||||
public String getOicTokenServerUrl() {
|
||||
return get(FessConfig.OIC_TOKEN_SERVER_URL);
|
||||
}
|
||||
|
||||
public String getOicDefaultRoles() {
|
||||
return get(FessConfig.OIC_DEFAULT_ROLES);
|
||||
}
|
||||
|
||||
public String getOicDefaultGroups() {
|
||||
return get(FessConfig.OIC_DEFAULT_GROUPS);
|
||||
}
|
||||
|
||||
public Integer getOicDefaultGroupsAsInteger() {
|
||||
return getAsInteger(FessConfig.OIC_DEFAULT_GROUPS);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected java.util.Map<String, String> prepareGeneratedDefaultMap() {
|
||||
java.util.Map<String, String> defaultMap = super.prepareGeneratedDefaultMap();
|
||||
|
@ -9018,28 +8618,6 @@ public interface FessConfig extends FessEnv, org.codelibs.fess.mylasta.direction
|
|||
defaultMap.put(FessConfig.LDAP_ATTR_UID_NUMBER, "uidNumber");
|
||||
defaultMap.put(FessConfig.LDAP_ATTR_GID_NUMBER, "gidNumber");
|
||||
defaultMap.put(FessConfig.LDAP_ATTR_HOME_DIRECTORY, "homeDirectory");
|
||||
defaultMap.put(FessConfig.SSO_TYPE, "none");
|
||||
defaultMap.put(FessConfig.SPNEGO_LOGGER_LEVEL, "");
|
||||
defaultMap.put(FessConfig.SPNEGO_KRB5_CONF, "krb5.conf");
|
||||
defaultMap.put(FessConfig.SPNEGO_LOGIN_CONF, "auth_login.conf");
|
||||
defaultMap.put(FessConfig.SPNEGO_PREAUTH_USERNAME, "username");
|
||||
defaultMap.put(FessConfig.SPNEGO_PREAUTH_PASSWORD, "password");
|
||||
defaultMap.put(FessConfig.SPNEGO_LOGIN_CLIENT_MODULE, "spnego-client");
|
||||
defaultMap.put(FessConfig.SPNEGO_LOGIN_SERVER_MODULE, "spnego-server");
|
||||
defaultMap.put(FessConfig.SPNEGO_ALLOW_BASIC, "true");
|
||||
defaultMap.put(FessConfig.SPNEGO_ALLOW_UNSECURE_BASIC, "true");
|
||||
defaultMap.put(FessConfig.SPNEGO_PROMPT_NTLM, "true");
|
||||
defaultMap.put(FessConfig.SPNEGO_ALLOW_LOCALHOST, "true");
|
||||
defaultMap.put(FessConfig.SPNEGO_ALLOW_DELEGATION, "false");
|
||||
defaultMap.put(FessConfig.SPNEGO_EXCLUDE_DIRS, "");
|
||||
defaultMap.put(FessConfig.OIC_CLIENT_ID, "__CLIENT_ID__");
|
||||
defaultMap.put(FessConfig.OIC_CLIENT_SECRET, "__CLIENT_SECRET__");
|
||||
defaultMap.put(FessConfig.OIC_AUTH_SERVER_URL, "https://accounts.google.com/o/oauth2/auth");
|
||||
defaultMap.put(FessConfig.OIC_REDIRECT_URL, "http://localhost:8080/sso/");
|
||||
defaultMap.put(FessConfig.OIC_SCOPE, "openid email");
|
||||
defaultMap.put(FessConfig.OIC_TOKEN_SERVER_URL, "https://accounts.google.com/o/oauth2/token");
|
||||
defaultMap.put(FessConfig.OIC_DEFAULT_ROLES, "guest");
|
||||
defaultMap.put(FessConfig.OIC_DEFAULT_GROUPS, "");
|
||||
defaultMap.put(FessConfig.lasta_di_SMART_DEPLOY_MODE, "hot");
|
||||
defaultMap.put(FessConfig.DEVELOPMENT_HERE, "true");
|
||||
defaultMap.put(FessConfig.ENVIRONMENT_TITLE, "Local Development");
|
||||
|
|
|
@ -1203,16 +1203,15 @@ public interface FessProp {
|
|||
return list;
|
||||
}
|
||||
|
||||
String getOicDefaultGroups();
|
||||
|
||||
default String[] getOicDefaultGroupsAsArray() {
|
||||
String[] array = (String[]) propMap.get(OIC_DEFAULT_GROUPS);
|
||||
if (array == null) {
|
||||
if (StringUtil.isBlank(getOicDefaultGroups())) {
|
||||
final String oicDefaultGroups = getSystemProperty("oic.default.groups");
|
||||
if (StringUtil.isBlank(oicDefaultGroups)) {
|
||||
array = StringUtil.EMPTY_STRINGS;
|
||||
} else {
|
||||
array =
|
||||
split(getOicDefaultGroups(), ",").get(
|
||||
split(oicDefaultGroups, ",").get(
|
||||
stream -> stream.filter(StringUtil::isNotBlank).map(s -> s.trim()).toArray(n -> new String[n]));
|
||||
}
|
||||
propMap.put(OIC_DEFAULT_GROUPS, array);
|
||||
|
@ -1220,16 +1219,15 @@ public interface FessProp {
|
|||
return array;
|
||||
}
|
||||
|
||||
String getOicDefaultRoles();
|
||||
|
||||
default String[] getOicDefaultRolesAsArray() {
|
||||
String[] array = (String[]) propMap.get(OIC_DEFAULT_ROLES);
|
||||
if (array == null) {
|
||||
if (StringUtil.isBlank(getOicDefaultRoles())) {
|
||||
final String oicDefaultRoles = getSystemProperty("oic.default.roles");
|
||||
if (StringUtil.isBlank(oicDefaultRoles)) {
|
||||
array = StringUtil.EMPTY_STRINGS;
|
||||
} else {
|
||||
array =
|
||||
split(getOicDefaultRoles(), ",").get(
|
||||
split(oicDefaultRoles, ",").get(
|
||||
stream -> stream.filter(StringUtil::isNotBlank).map(s -> s.trim()).toArray(n -> new String[n]));
|
||||
}
|
||||
propMap.put(OIC_DEFAULT_ROLES, array);
|
||||
|
@ -1927,7 +1925,7 @@ public interface FessProp {
|
|||
List<Pair<String, String>> list = (List<Pair<String, String>>) propMap.get(API_GSA_RESPONSE_HEADER_LIST);
|
||||
if (list == null) {
|
||||
list = split(getApiGsaResponseHeaders(), "\n").get(stream -> stream.filter(StringUtil::isNotBlank).map(s -> {
|
||||
String[] values = s.split(":", 2);
|
||||
final String[] values = s.split(":", 2);
|
||||
if (values.length == 2) {
|
||||
return new Pair<>(values[0], values[1]);
|
||||
}
|
||||
|
@ -1944,7 +1942,7 @@ public interface FessProp {
|
|||
List<Pair<String, String>> list = (List<Pair<String, String>>) propMap.get(API_JSON_RESPONSE_HEADER_LIST);
|
||||
if (list == null) {
|
||||
list = split(getApiJsonResponseHeaders(), "\n").get(stream -> stream.filter(StringUtil::isNotBlank).map(s -> {
|
||||
String[] values = s.split(":", 2);
|
||||
final String[] values = s.split(":", 2);
|
||||
if (values.length == 2) {
|
||||
return new Pair<>(values[0], values[1]);
|
||||
}
|
||||
|
@ -1961,7 +1959,7 @@ public interface FessProp {
|
|||
List<Pair<String, String>> list = (List<Pair<String, String>>) propMap.get(API_DASHBOARD_RESPONSE_HEADER_LIST);
|
||||
if (list == null) {
|
||||
list = split(getApiDashboardResponseHeaders(), "\n").get(stream -> stream.filter(StringUtil::isNotBlank).map(s -> {
|
||||
String[] values = s.split(":", 2);
|
||||
final String[] values = s.split(":", 2);
|
||||
if (values.length == 2) {
|
||||
return new Pair<>(values[0], values[1]);
|
||||
}
|
||||
|
|
|
@ -15,10 +15,13 @@
|
|||
*/
|
||||
package org.codelibs.fess.sso;
|
||||
|
||||
import org.codelibs.fess.app.web.base.login.FessLoginAssist.LoginCredentialResolver;
|
||||
import org.lastaflute.web.login.credential.LoginCredential;
|
||||
|
||||
public interface SsoAuthenticator {
|
||||
|
||||
LoginCredential getLoginCredential();
|
||||
|
||||
void resolveCredential(LoginCredentialResolver resolver);
|
||||
|
||||
}
|
|
@ -15,31 +15,47 @@
|
|||
*/
|
||||
package org.codelibs.fess.sso;
|
||||
|
||||
import javax.annotation.PostConstruct;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.codelibs.fess.util.ComponentUtil;
|
||||
import org.lastaflute.web.login.credential.LoginCredential;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
public class SsoManager {
|
||||
private static final Logger logger = LoggerFactory.getLogger(SsoManager.class);
|
||||
|
||||
private SsoAuthenticator authenticator;
|
||||
protected static final String SSO_TYPE = "sso.type";
|
||||
|
||||
@PostConstruct
|
||||
public void init() {
|
||||
final String ssoType = ComponentUtil.getFessConfig().getSsoType();
|
||||
if (!"none".equals(ssoType)) {
|
||||
authenticator = ComponentUtil.getComponent(ssoType + "Authenticator");
|
||||
}
|
||||
}
|
||||
protected static final String NONE = "none";
|
||||
|
||||
protected final List<SsoAuthenticator> authenticatorList = new ArrayList<>();
|
||||
|
||||
public boolean available() {
|
||||
return authenticator != null;
|
||||
return !NONE.equals(getSsoType());
|
||||
}
|
||||
|
||||
public LoginCredential getLoginCredential() {
|
||||
if (authenticator != null) {
|
||||
if (available()) {
|
||||
final SsoAuthenticator authenticator = ComponentUtil.getComponent(getSsoType() + "Authenticator");
|
||||
return authenticator.getLoginCredential();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
protected String getSsoType() {
|
||||
return ComponentUtil.getFessConfig().getSystemProperty(SSO_TYPE, NONE);
|
||||
}
|
||||
|
||||
public SsoAuthenticator[] getAuthenticators() {
|
||||
return authenticatorList.toArray(new SsoAuthenticator[authenticatorList.size()]);
|
||||
}
|
||||
|
||||
public void register(final SsoAuthenticator authenticator) {
|
||||
if (logger.isInfoEnabled()) {
|
||||
logger.info("Load " + authenticator.getClass().getSimpleName());
|
||||
}
|
||||
authenticatorList.add(authenticator);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,305 @@
|
|||
/*
|
||||
* Copyright 2012-2019 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.aad;
|
||||
|
||||
import java.net.URI;
|
||||
import java.net.URLEncoder;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.Executors;
|
||||
import java.util.concurrent.Future;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import javax.annotation.PostConstruct;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpSession;
|
||||
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.codelibs.core.lang.StringUtil;
|
||||
import org.codelibs.core.net.UuidUtil;
|
||||
import org.codelibs.fess.app.web.base.login.ActionResponseCredential;
|
||||
import org.codelibs.fess.app.web.base.login.AzureAdCredential;
|
||||
import org.codelibs.fess.app.web.base.login.FessLoginAssist.LoginCredentialResolver;
|
||||
import org.codelibs.fess.app.web.base.login.OpenIdConnectCredential;
|
||||
import org.codelibs.fess.crawler.Constants;
|
||||
import org.codelibs.fess.exception.SsoLoginException;
|
||||
import org.codelibs.fess.sso.SsoAuthenticator;
|
||||
import org.codelibs.fess.util.ComponentUtil;
|
||||
import org.dbflute.optional.OptionalEntity;
|
||||
import org.lastaflute.web.login.credential.LoginCredential;
|
||||
import org.lastaflute.web.response.HtmlResponse;
|
||||
import org.lastaflute.web.util.LaRequestUtil;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import com.microsoft.aad.adal4j.AuthenticationContext;
|
||||
import com.microsoft.aad.adal4j.AuthenticationResult;
|
||||
import com.microsoft.aad.adal4j.ClientCredential;
|
||||
import com.nimbusds.jwt.JWTClaimsSet;
|
||||
import com.nimbusds.jwt.JWTParser;
|
||||
import com.nimbusds.oauth2.sdk.AuthorizationCode;
|
||||
import com.nimbusds.openid.connect.sdk.AuthenticationErrorResponse;
|
||||
import com.nimbusds.openid.connect.sdk.AuthenticationResponse;
|
||||
import com.nimbusds.openid.connect.sdk.AuthenticationResponseParser;
|
||||
import com.nimbusds.openid.connect.sdk.AuthenticationSuccessResponse;
|
||||
|
||||
public class AzureAdAuthenticator implements SsoAuthenticator {
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(AzureAdAuthenticator.class);
|
||||
|
||||
protected static final String AZUREAD_STATE_TTL = "azuread.state.ttl";
|
||||
|
||||
protected static final String AZUREAD_AUTHORITY = "azuread.authority";
|
||||
|
||||
protected static final String AZUREAD_TENANT = "azuread.tenant";
|
||||
|
||||
protected static final String AZUREAD_CLIENT_SECRET = "azuread.client.secret";
|
||||
|
||||
protected static final String AZUREAD_CLIENT_ID = "azuread.client.id";
|
||||
|
||||
protected static final String STATES = "aadStates";
|
||||
|
||||
protected static final String STATE = "aadState";
|
||||
|
||||
protected static final String ERROR = "error";
|
||||
|
||||
protected static final String ERROR_DESCRIPTION = "error_description";
|
||||
|
||||
protected static final String ERROR_URI = "error_uri";
|
||||
|
||||
protected static final String ID_TOKEN = "id_token";
|
||||
|
||||
protected static final String CODE = "code";
|
||||
|
||||
@PostConstruct
|
||||
public void init() {
|
||||
ComponentUtil.getSsoManager().register(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public LoginCredential getLoginCredential() {
|
||||
return LaRequestUtil.getOptionalRequest().map(request -> {
|
||||
final HttpSession session = request.getSession(false);
|
||||
if (session != null && containsAuthenticationData(request)) {
|
||||
try {
|
||||
return processAuthenticationData(request);
|
||||
} catch (final Exception e) {
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Failed to process a login request on AzureAD.", e);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
// TODO refresh
|
||||
|
||||
return new ActionResponseCredential(() -> HtmlResponse.fromRedirectPathAsIs(getAuthUrl(request)));
|
||||
}).orElse(null);
|
||||
}
|
||||
|
||||
protected String getAuthUrl(final HttpServletRequest request) {
|
||||
final String state = UuidUtil.create();
|
||||
final String nonce = UuidUtil.create();
|
||||
storeStateInSession(request.getSession(), state, nonce);
|
||||
return getAuthority() + getTenant()
|
||||
+ "/oauth2/authorize?response_type=code&scope=directory.read.all&response_mode=form_post&redirect_uri="
|
||||
+ URLEncoder.encode(request.getRequestURL().toString(), Constants.UTF_8_CHARSET) + "&client_id=" + getClientId()
|
||||
+ "&resource=https%3a%2f%2fgraph.microsoft.com" + "&state=" + state + "&nonce=" + nonce;
|
||||
|
||||
}
|
||||
|
||||
protected void storeStateInSession(final HttpSession session, final String state, final String nonce) {
|
||||
@SuppressWarnings("unchecked")
|
||||
Map<String, StateData> stateMap = (Map<String, StateData>) session.getAttribute(STATES);
|
||||
if (stateMap == null) {
|
||||
stateMap = new HashMap<>();
|
||||
session.setAttribute(STATES, stateMap);
|
||||
}
|
||||
stateMap.put(state, new StateData(nonce, System.currentTimeMillis()));
|
||||
}
|
||||
|
||||
protected LoginCredential processAuthenticationData(final HttpServletRequest request) {
|
||||
final StringBuffer urlBuf = request.getRequestURL();
|
||||
final String queryStr = request.getQueryString();
|
||||
if (queryStr != null) {
|
||||
urlBuf.append('?').append(queryStr);
|
||||
}
|
||||
|
||||
final Map<String, String> params = new HashMap<>();
|
||||
for (final Map.Entry<String, String[]> e : request.getParameterMap().entrySet()) {
|
||||
if (e.getValue().length > 0) {
|
||||
params.put(e.getKey(), e.getValue()[0]);
|
||||
}
|
||||
}
|
||||
|
||||
// validate that state in response equals to state in request
|
||||
final StateData stateData = validateState(request.getSession(), params.get(STATE));
|
||||
|
||||
final AuthenticationResponse authResponse = parseAuthenticationResponse(urlBuf.toString(), params);
|
||||
if (authResponse instanceof AuthenticationSuccessResponse) {
|
||||
final AuthenticationSuccessResponse oidcResponse = (AuthenticationSuccessResponse) authResponse;
|
||||
// validate that OIDC Auth Response matches Code Flow (contains only requested artifacts)
|
||||
validateAuthRespMatchesCodeFlow(oidcResponse);
|
||||
|
||||
final AuthenticationResult authData = getAccessToken(oidcResponse.getAuthorizationCode(), request.getRequestURL().toString());
|
||||
// validate nonce to prevent reply attacks (code maybe substituted to one with broader access)
|
||||
|
||||
validateNonce(stateData, authData);
|
||||
|
||||
return new AzureAdCredential(authData);
|
||||
} else {
|
||||
final AuthenticationErrorResponse oidcResponse = (AuthenticationErrorResponse) authResponse;
|
||||
throw new SsoLoginException(String.format("Request for auth code failed: %s - %s", oidcResponse.getErrorObject().getCode(),
|
||||
oidcResponse.getErrorObject().getDescription()));
|
||||
}
|
||||
}
|
||||
|
||||
protected AuthenticationResponse parseAuthenticationResponse(final String url, final Map<String, String> params) {
|
||||
try {
|
||||
return AuthenticationResponseParser.parse(new URI(url), params);
|
||||
} catch (final Exception e) {
|
||||
throw new SsoLoginException("Failed to parse an authentication response.", e);
|
||||
}
|
||||
}
|
||||
|
||||
protected void validateNonce(final StateData stateData, final AuthenticationResult authData) {
|
||||
final String idToken = authData.getIdToken();
|
||||
try {
|
||||
final JWTClaimsSet claimsSet = JWTParser.parse(idToken).getJWTClaimsSet();
|
||||
if (claimsSet == null) {
|
||||
throw new SsoLoginException("could not validate nonce");
|
||||
}
|
||||
|
||||
final String nonce = (String) claimsSet.getClaim("nonce");
|
||||
if (StringUtils.isEmpty(nonce) || !nonce.equals(stateData.getNonce())) {
|
||||
throw new SsoLoginException("could not validate nonce");
|
||||
}
|
||||
} catch (final SsoLoginException e) {
|
||||
throw e;
|
||||
} catch (final Exception e) {
|
||||
throw new SsoLoginException("could not validate nonce", e);
|
||||
}
|
||||
}
|
||||
|
||||
protected AuthenticationResult getAccessToken(final AuthorizationCode authorizationCode, final String currentUri) {
|
||||
final String authCode = authorizationCode.getValue();
|
||||
final ClientCredential credential = new ClientCredential(getClientId(), getClientSecret());
|
||||
ExecutorService service = null;
|
||||
try {
|
||||
service = Executors.newFixedThreadPool(1);// TODO replace with something...
|
||||
final AuthenticationContext context = new AuthenticationContext(getAuthority() + getTenant() + "/", true, service);
|
||||
final Future<AuthenticationResult> future =
|
||||
context.acquireTokenByAuthorizationCode(authCode, new URI(currentUri), credential, null);
|
||||
final AuthenticationResult result = future.get();
|
||||
if (result == null) {
|
||||
throw new SsoLoginException("authentication result was null");
|
||||
}
|
||||
return result;
|
||||
} catch (final Exception e) {
|
||||
throw new SsoLoginException("Failed to get a token.", e);
|
||||
} finally {
|
||||
if (service != null) {
|
||||
service.shutdown();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected void validateAuthRespMatchesCodeFlow(final AuthenticationSuccessResponse oidcResponse) {
|
||||
if (oidcResponse.getIDToken() != null || oidcResponse.getAccessToken() != null || oidcResponse.getAuthorizationCode() == null) {
|
||||
throw new SsoLoginException("unexpected set of artifacts received");
|
||||
}
|
||||
}
|
||||
|
||||
protected StateData validateState(final HttpSession session, final String state) {
|
||||
if (StringUtils.isNotEmpty(state)) {
|
||||
final StateData stateDataInSession = removeStateFromSession(session, state);
|
||||
if (stateDataInSession != null) {
|
||||
return stateDataInSession;
|
||||
}
|
||||
}
|
||||
throw new SsoLoginException("could not validate state");
|
||||
}
|
||||
|
||||
protected StateData removeStateFromSession(final HttpSession session, final String state) {
|
||||
@SuppressWarnings("unchecked")
|
||||
final Map<String, StateData> states = (Map<String, StateData>) session.getAttribute(STATES);
|
||||
if (states != null) {
|
||||
final long now = System.currentTimeMillis();
|
||||
states.entrySet().stream().filter(e -> (now - e.getValue().getExpiration()) / 1000L > getStateTtl()).map(Map.Entry::getKey)
|
||||
.collect(Collectors.toList()).forEach(s -> states.remove(s));
|
||||
final StateData stateData = states.get(state);
|
||||
if (stateData != null) {
|
||||
states.remove(state);
|
||||
return stateData;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
protected boolean containsAuthenticationData(final HttpServletRequest request) {
|
||||
if (!request.getMethod().equalsIgnoreCase("POST")) {
|
||||
return false;
|
||||
}
|
||||
final Map<String, String[]> params = request.getParameterMap();
|
||||
return params.containsKey(ERROR) || params.containsKey(ID_TOKEN) || params.containsKey(CODE);
|
||||
}
|
||||
|
||||
protected class StateData {
|
||||
private final String nonce;
|
||||
private final long expiration;
|
||||
|
||||
public StateData(final String nonce, final long expiration) {
|
||||
this.nonce = nonce;
|
||||
this.expiration = expiration;
|
||||
}
|
||||
|
||||
public String getNonce() {
|
||||
return nonce;
|
||||
}
|
||||
|
||||
public long getExpiration() {
|
||||
return expiration;
|
||||
}
|
||||
}
|
||||
|
||||
protected String getClientId() {
|
||||
return ComponentUtil.getFessConfig().getSystemProperty(AZUREAD_CLIENT_ID, StringUtil.EMPTY);
|
||||
}
|
||||
|
||||
protected String getClientSecret() {
|
||||
return ComponentUtil.getFessConfig().getSystemProperty(AZUREAD_CLIENT_SECRET, StringUtil.EMPTY);
|
||||
}
|
||||
|
||||
protected String getTenant() {
|
||||
return ComponentUtil.getFessConfig().getSystemProperty(AZUREAD_TENANT, StringUtil.EMPTY);
|
||||
}
|
||||
|
||||
protected String getAuthority() {
|
||||
return ComponentUtil.getFessConfig().getSystemProperty(AZUREAD_AUTHORITY, StringUtil.EMPTY);
|
||||
}
|
||||
|
||||
protected long getStateTtl() {
|
||||
return Long.parseLong(ComponentUtil.getFessConfig().getSystemProperty(AZUREAD_STATE_TTL, "3600"));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void resolveCredential(final LoginCredentialResolver resolver) {
|
||||
resolver.resolve(OpenIdConnectCredential.class, credential -> {
|
||||
return OptionalEntity.of(credential.getUser());
|
||||
});
|
||||
}
|
||||
}
|
|
@ -20,17 +20,19 @@ import java.util.Arrays;
|
|||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import javax.annotation.PostConstruct;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpSession;
|
||||
|
||||
import org.codelibs.core.lang.StringUtil;
|
||||
import org.codelibs.core.net.UuidUtil;
|
||||
import org.codelibs.fess.app.web.base.login.ActionResponseCredential;
|
||||
import org.codelibs.fess.app.web.base.login.FessLoginAssist.LoginCredentialResolver;
|
||||
import org.codelibs.fess.app.web.base.login.OpenIdConnectCredential;
|
||||
import org.codelibs.fess.crawler.Constants;
|
||||
import org.codelibs.fess.mylasta.direction.FessConfig;
|
||||
import org.codelibs.fess.sso.SsoAuthenticator;
|
||||
import org.codelibs.fess.util.ComponentUtil;
|
||||
import org.dbflute.optional.OptionalEntity;
|
||||
import org.lastaflute.web.login.credential.LoginCredential;
|
||||
import org.lastaflute.web.response.HtmlResponse;
|
||||
import org.lastaflute.web.util.LaRequestUtil;
|
||||
|
@ -53,11 +55,28 @@ public class OpenIdConnectAuthenticator implements SsoAuthenticator {
|
|||
|
||||
private static final Logger logger = LoggerFactory.getLogger(OpenIdConnectAuthenticator.class);
|
||||
|
||||
private static final String OIC_STATE = "OIC_STATE";
|
||||
protected static final String OIC_AUTH_SERVER_URL = "oic.auth.server.url";
|
||||
|
||||
private final HttpTransport httpTransport = new NetHttpTransport();
|
||||
protected static final String OIC_CLIENT_ID = "oic.client.id";
|
||||
|
||||
private final JsonFactory jsonFactory = JacksonFactory.getDefaultInstance();
|
||||
protected static final String OIC_SCOPE = "oic.scope";
|
||||
|
||||
protected static final String OIC_REDIRECT_URL = "oic.redirect.url";
|
||||
|
||||
protected static final String OIC_TOKEN_SERVER_URL = "oic.token.server.url";
|
||||
|
||||
protected static final String OIC_CLIENT_SECRET = "oic.client.secret";
|
||||
|
||||
protected static final String OIC_STATE = "OIC_STATE";
|
||||
|
||||
protected final HttpTransport httpTransport = new NetHttpTransport();
|
||||
|
||||
protected final JsonFactory jsonFactory = JacksonFactory.getDefaultInstance();
|
||||
|
||||
@PostConstruct
|
||||
public void init() {
|
||||
ComponentUtil.getSsoManager().register(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public LoginCredential getLoginCredential() {
|
||||
|
@ -84,13 +103,12 @@ public class OpenIdConnectAuthenticator implements SsoAuthenticator {
|
|||
}
|
||||
|
||||
protected String getAuthUrl(final HttpServletRequest request) {
|
||||
final FessConfig fessConfig = ComponentUtil.getFessConfig();
|
||||
final String state = UuidUtil.create();
|
||||
request.getSession().setAttribute(OIC_STATE, state);
|
||||
return new AuthorizationCodeRequestUrl(fessConfig.getOicAuthServerUrl(), fessConfig.getOicClientId())//
|
||||
.setScopes(Arrays.asList(fessConfig.getOicScope()))//
|
||||
return new AuthorizationCodeRequestUrl(getOicAuthServerUrl(), getOicClientId())//
|
||||
.setScopes(Arrays.asList(getOicScope()))//
|
||||
.setResponseTypes(Arrays.asList("code"))//
|
||||
.setRedirectUri(fessConfig.getOicRedirectUrl())//
|
||||
.setRedirectUri(getOicRedirectUrl())//
|
||||
.setState(state)//
|
||||
.build();
|
||||
}
|
||||
|
@ -174,12 +192,42 @@ public class OpenIdConnectAuthenticator implements SsoAuthenticator {
|
|||
}
|
||||
|
||||
protected TokenResponse getTokenUrl(final String code) throws IOException {
|
||||
final FessConfig fessConfig = ComponentUtil.getFessConfig();
|
||||
return new AuthorizationCodeTokenRequest(httpTransport, jsonFactory, new GenericUrl(fessConfig.getOicTokenServerUrl()), code)//
|
||||
return new AuthorizationCodeTokenRequest(httpTransport, jsonFactory, new GenericUrl(getOicTokenServerUrl()), code)//
|
||||
.setGrantType("authorization_code")//
|
||||
.setRedirectUri(fessConfig.getOicRedirectUrl())//
|
||||
.set("client_id", fessConfig.getOicClientId())//
|
||||
.set("client_secret", fessConfig.getOicClientSecret())//
|
||||
.setRedirectUri(getOicRedirectUrl())//
|
||||
.set("client_id", getOicClientId())//
|
||||
.set("client_secret", getOicClientSecret())//
|
||||
.execute();
|
||||
}
|
||||
|
||||
protected String getOicClientSecret() {
|
||||
return ComponentUtil.getSystemProperties().getProperty(OIC_CLIENT_SECRET, StringUtil.EMPTY);
|
||||
}
|
||||
|
||||
protected String getOicTokenServerUrl() {
|
||||
return ComponentUtil.getSystemProperties().getProperty(OIC_TOKEN_SERVER_URL, "https://accounts.google.com/o/oauth2/token");
|
||||
}
|
||||
|
||||
protected String getOicRedirectUrl() {
|
||||
return ComponentUtil.getSystemProperties().getProperty(OIC_REDIRECT_URL, "http://localhost:8080/sso/");
|
||||
}
|
||||
|
||||
protected String getOicScope() {
|
||||
return ComponentUtil.getSystemProperties().getProperty(OIC_SCOPE, StringUtil.EMPTY);
|
||||
}
|
||||
|
||||
protected String getOicClientId() {
|
||||
return ComponentUtil.getSystemProperties().getProperty(OIC_CLIENT_ID, StringUtil.EMPTY);
|
||||
}
|
||||
|
||||
protected String getOicAuthServerUrl() {
|
||||
return ComponentUtil.getSystemProperties().getProperty(OIC_AUTH_SERVER_URL, "https://accounts.google.com/o/oauth2/auth");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void resolveCredential(final LoginCredentialResolver resolver) {
|
||||
resolver.resolve(OpenIdConnectCredential.class, credential -> {
|
||||
return OptionalEntity.of(credential.getUser());
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
@ -26,10 +26,9 @@ import javax.servlet.http.HttpServletResponse;
|
|||
import org.codelibs.core.io.ResourceUtil;
|
||||
import org.codelibs.core.lang.StringUtil;
|
||||
import org.codelibs.fess.app.web.base.login.ActionResponseCredential;
|
||||
import org.codelibs.fess.app.web.base.login.FessLoginAssist.LoginCredentialResolver;
|
||||
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;
|
||||
|
@ -37,6 +36,7 @@ import org.codelibs.spnego.SpnegoHttpFilter;
|
|||
import org.codelibs.spnego.SpnegoHttpFilter.Constants;
|
||||
import org.codelibs.spnego.SpnegoHttpServletResponse;
|
||||
import org.codelibs.spnego.SpnegoPrincipal;
|
||||
import org.dbflute.optional.OptionalEntity;
|
||||
import org.lastaflute.web.login.credential.LoginCredential;
|
||||
import org.lastaflute.web.servlet.filter.RequestLoggingFilter;
|
||||
import org.lastaflute.web.util.LaRequestUtil;
|
||||
|
@ -47,19 +47,37 @@ import org.slf4j.LoggerFactory;
|
|||
public class SpnegoAuthenticator implements SsoAuthenticator {
|
||||
private static final Logger logger = LoggerFactory.getLogger(SpnegoAuthenticator.class);
|
||||
|
||||
protected static final String SPNEGO_EXCLUDE_DIRS = "spnego.exclude.dirs";
|
||||
protected static final String SPNEGO_ALLOW_DELEGATION = "spnego.allow.delegation";
|
||||
protected static final String SPNEGO_ALLOW_LOCALHOST = "spnego.allow.localhost";
|
||||
protected static final String SPNEGO_PROMPT_NTLM = "spnego.prompt.ntlm";
|
||||
protected static final String SPNEGO_ALLOW_UNSECURE_BASIC = "spnego.allow.unsecure.basic";
|
||||
protected static final String SPNEGO_ALLOW_BASIC = "spnego.allow.basic";
|
||||
protected static final String SPNEGO_PREAUTH_PASSWORD = "spnego.preauth.password";
|
||||
protected static final String SPNEGO_PREAUTH_USERNAME = "spnego.preauth.username";
|
||||
protected static final String SPNEGO_LOGIN_SERVER_MODULE = "spnego.login.server.module";
|
||||
protected static final String SPNEGO_LOGIN_CLIENT_MODULE = "spnego.login.client.module";
|
||||
protected static final String SPNEGO_KRB5_CONF = "spnego.krb5.conf";
|
||||
protected static final String SPNEGO_LOGIN_CONF = "spnego.login.conf";
|
||||
protected static final String SPNEGO_LOGGER_LEVEL = "spnego.logger.level";
|
||||
|
||||
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());
|
||||
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);
|
||||
// pre-authenticate
|
||||
authenticator = new org.codelibs.spnego.SpnegoAuthenticator(config);
|
||||
|
||||
ComponentUtil.getSsoManager().register(this);
|
||||
} catch (final Exception e) {
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.warn("Failed to initialize SPNEGO.", e);
|
||||
} else {
|
||||
logger.warn("Failed to initialize SPNEGO.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -116,8 +134,6 @@ public class SpnegoAuthenticator implements SsoAuthenticator {
|
|||
|
||||
protected class SpengoConfig implements FilterConfig {
|
||||
|
||||
protected FessConfig fessConfig = ComponentUtil.getFessConfig();
|
||||
|
||||
@Override
|
||||
public String getFilterName() {
|
||||
return SpnegoAuthenticator.class.getName();
|
||||
|
@ -131,8 +147,9 @@ public class SpnegoAuthenticator implements SsoAuthenticator {
|
|||
@Override
|
||||
public String getInitParameter(final String name) {
|
||||
if (SpnegoHttpFilter.Constants.LOGGER_LEVEL.equals(name)) {
|
||||
if (StringUtil.isNotBlank(fessConfig.getSpnegoLoggerLevel())) {
|
||||
return fessConfig.getSpnegoLoggerLevel();
|
||||
final String logLevel = getProperty(SPNEGO_LOGGER_LEVEL, StringUtil.EMPTY);
|
||||
if (StringUtil.isNotBlank(logLevel)) {
|
||||
return logLevel;
|
||||
} else if (logger.isDebugEnabled()) {
|
||||
return "3";
|
||||
} else if (logger.isInfoEnabled()) {
|
||||
|
@ -145,33 +162,37 @@ public class SpnegoAuthenticator implements SsoAuthenticator {
|
|||
return "0";
|
||||
}
|
||||
} else if (SpnegoHttpFilter.Constants.LOGIN_CONF.equals(name)) {
|
||||
return getResourcePath(fessConfig.getSpnegoLoginConf());
|
||||
return getResourcePath(getProperty(SPNEGO_LOGIN_CONF, "auth_login.conf"));
|
||||
} else if (SpnegoHttpFilter.Constants.KRB5_CONF.equals(name)) {
|
||||
return getResourcePath(fessConfig.getSpnegoKrb5Conf());
|
||||
return getResourcePath(getProperty(SPNEGO_KRB5_CONF, "krb5.conf"));
|
||||
} else if (SpnegoHttpFilter.Constants.CLIENT_MODULE.equals(name)) {
|
||||
return fessConfig.getSpnegoLoginClientModule();
|
||||
return getProperty(SPNEGO_LOGIN_CLIENT_MODULE, "spnego-client");
|
||||
} else if (SpnegoHttpFilter.Constants.SERVER_MODULE.equals(name)) {
|
||||
return fessConfig.getSpnegoLoginServerModule();
|
||||
return getProperty(SPNEGO_LOGIN_SERVER_MODULE, "spnego-server");
|
||||
} else if (SpnegoHttpFilter.Constants.PREAUTH_USERNAME.equals(name)) {
|
||||
return fessConfig.getSpnegoPreauthUsername();
|
||||
return getProperty(SPNEGO_PREAUTH_USERNAME, "username");
|
||||
} else if (SpnegoHttpFilter.Constants.PREAUTH_PASSWORD.equals(name)) {
|
||||
return fessConfig.getSpnegoPreauthPassword();
|
||||
return getProperty(SPNEGO_PREAUTH_PASSWORD, "password");
|
||||
} else if (SpnegoHttpFilter.Constants.ALLOW_BASIC.equals(name)) {
|
||||
return fessConfig.getSpnegoAllowBasic();
|
||||
return getProperty(SPNEGO_ALLOW_BASIC, "true");
|
||||
} else if (SpnegoHttpFilter.Constants.ALLOW_UNSEC_BASIC.equals(name)) {
|
||||
return fessConfig.getSpnegoAllowUnsecureBasic();
|
||||
return getProperty(SPNEGO_ALLOW_UNSECURE_BASIC, "true");
|
||||
} else if (SpnegoHttpFilter.Constants.PROMPT_NTLM.equals(name)) {
|
||||
return fessConfig.getSpnegoPromptNtlm();
|
||||
return getProperty(SPNEGO_PROMPT_NTLM, "true");
|
||||
} else if (SpnegoHttpFilter.Constants.ALLOW_LOCALHOST.equals(name)) {
|
||||
return fessConfig.getSpnegoAllowLocalhost();
|
||||
return getProperty(SPNEGO_ALLOW_LOCALHOST, "true");
|
||||
} else if (SpnegoHttpFilter.Constants.ALLOW_DELEGATION.equals(name)) {
|
||||
return fessConfig.getSpnegoAllowDelegation();
|
||||
return getProperty(SPNEGO_ALLOW_DELEGATION, "false");
|
||||
} else if (SpnegoHttpFilter.Constants.EXCLUDE_DIRS.equals(name)) {
|
||||
return fessConfig.getSpnegoExcludeDirs();
|
||||
return getProperty(SPNEGO_EXCLUDE_DIRS, StringUtil.EMPTY);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
protected String getProperty(final String key, final String defaultValue) {
|
||||
return ComponentUtil.getSystemProperties().getProperty(key, defaultValue);
|
||||
}
|
||||
|
||||
protected String getResourcePath(final String path) {
|
||||
final File file = ResourceUtil.getResourceAsFileNoException(path);
|
||||
if (file != null) {
|
||||
|
@ -186,4 +207,15 @@ public class SpnegoAuthenticator implements SsoAuthenticator {
|
|||
}
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void resolveCredential(final LoginCredentialResolver resolver) {
|
||||
resolver.resolve(SpnegoCredential.class, credential -> {
|
||||
final String username = credential.getUserId();
|
||||
if (!ComponentUtil.getFessConfig().isAdminUser(username)) {
|
||||
return ComponentUtil.getLdapManager().login(username);
|
||||
}
|
||||
return OptionalEntity.empty();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
@ -686,26 +686,26 @@ ldap.attr.homeDirectory=homeDirectory
|
|||
# ----------------------------------------------------------
|
||||
# SSO
|
||||
# ------
|
||||
sso.type=none
|
||||
spnego.logger.level=
|
||||
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
|
||||
spnego.exclude.dirs=
|
||||
#sso.type=none
|
||||
#spnego.logger.level=
|
||||
#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
|
||||
#spnego.exclude.dirs=
|
||||
|
||||
oic.client.id=__CLIENT_ID__
|
||||
oic.client.secret=__CLIENT_SECRET__
|
||||
oic.auth.server.url=https://accounts.google.com/o/oauth2/auth
|
||||
oic.redirect.url=http://localhost:8080/sso/
|
||||
oic.scope=openid email
|
||||
oic.token.server.url=https://accounts.google.com/o/oauth2/token
|
||||
oic.default.roles=guest
|
||||
oic.default.groups=
|
||||
#oic.client.id=__CLIENT_ID__
|
||||
#oic.client.secret=__CLIENT_SECRET__
|
||||
#oic.auth.server.url=https://accounts.google.com/o/oauth2/auth
|
||||
#oic.redirect.url=http://localhost:8080/sso/
|
||||
#oic.scope=openid email
|
||||
#oic.token.server.url=https://accounts.google.com/o/oauth2/token
|
||||
#oic.default.roles=guest
|
||||
#oic.default.groups=
|
||||
|
|
11
src/main/resources/fess_sso++.xml
Normal file
11
src/main/resources/fess_sso++.xml
Normal file
|
@ -0,0 +1,11 @@
|
|||
<?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="aadAuthenticator" class="org.codelibs.fess.sso.aad.AzureAdAuthenticator">
|
||||
</component>
|
||||
<component name="oicAuthenticator" class="org.codelibs.fess.sso.oic.OpenIdConnectAuthenticator">
|
||||
</component>
|
||||
<component name="spnegoAuthenticator" class="org.codelibs.fess.sso.spnego.SpnegoAuthenticator">
|
||||
</component>
|
||||
</components>
|
|
@ -4,10 +4,4 @@
|
|||
<components>
|
||||
<component name="ssoManager" class="org.codelibs.fess.sso.SsoManager">
|
||||
</component>
|
||||
|
||||
<component name="spnegoAuthenticator" class="org.codelibs.fess.sso.spnego.SpnegoAuthenticator">
|
||||
</component>
|
||||
<component name="oicAuthenticator" class="org.codelibs.fess.sso.oic.OpenIdConnectAuthenticator">
|
||||
</component>
|
||||
|
||||
</components>
|
||||
|
|
Loading…
Add table
Reference in a new issue