fix #2058 add roles/groups
This commit is contained in:
parent
b4029ba2ef
commit
ccdd233d9e
2 changed files with 108 additions and 35 deletions
|
@ -15,13 +15,11 @@
|
|||
*/
|
||||
package org.codelibs.fess.app.web.base.login;
|
||||
|
||||
import static org.codelibs.core.stream.StreamUtil.split;
|
||||
import static org.codelibs.core.stream.StreamUtil.stream;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
import org.codelibs.core.lang.StringUtil;
|
||||
import org.codelibs.fess.entity.FessUser;
|
||||
import org.codelibs.fess.helper.SystemHelper;
|
||||
import org.codelibs.fess.sso.aad.AzureAdAuthenticator;
|
||||
|
@ -49,25 +47,7 @@ public class AzureAdCredential implements LoginCredential, FessCredential {
|
|||
}
|
||||
|
||||
public AzureAdUser getUser() {
|
||||
return new AzureAdUser(authResult, getDefaultGroupsAsArray(), getDefaultRolesAsArray());
|
||||
}
|
||||
|
||||
protected static String[] getDefaultGroupsAsArray() {
|
||||
final String value = ComponentUtil.getFessConfig().getSystemProperty("azuread.default.groups");
|
||||
if (StringUtil.isBlank(value)) {
|
||||
return StringUtil.EMPTY_STRINGS;
|
||||
} else {
|
||||
return split(value, ",").get(stream -> stream.filter(StringUtil::isNotBlank).map(s -> s.trim()).toArray(n -> new String[n]));
|
||||
}
|
||||
}
|
||||
|
||||
protected static String[] getDefaultRolesAsArray() {
|
||||
final String value = ComponentUtil.getFessConfig().getSystemProperty("azuread.default.roles");
|
||||
if (StringUtil.isBlank(value)) {
|
||||
return StringUtil.EMPTY_STRINGS;
|
||||
} else {
|
||||
return split(value, ",").get(stream -> stream.filter(StringUtil::isNotBlank).map(s -> s.trim()).toArray(n -> new String[n]));
|
||||
}
|
||||
return new AzureAdUser(authResult);
|
||||
}
|
||||
|
||||
public static class AzureAdUser implements FessUser {
|
||||
|
@ -81,10 +61,10 @@ public class AzureAdCredential implements LoginCredential, FessCredential {
|
|||
|
||||
protected AuthenticationResult authResult;
|
||||
|
||||
public AzureAdUser(final AuthenticationResult authResult, final String[] groups, final String[] roles) {
|
||||
public AzureAdUser(final AuthenticationResult authResult) {
|
||||
this.authResult = authResult;
|
||||
this.groups = groups;
|
||||
this.roles = roles;
|
||||
final AzureAdAuthenticator authenticator = ComponentUtil.getComponent(AzureAdAuthenticator.class);
|
||||
authenticator.updateMemberOf(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -123,7 +103,21 @@ public class AzureAdCredential implements LoginCredential, FessCredential {
|
|||
final AzureAdAuthenticator authenticator = ComponentUtil.getComponent(AzureAdAuthenticator.class);
|
||||
final String refreshToken = authResult.getRefreshToken();
|
||||
authResult = authenticator.getAccessToken(refreshToken);
|
||||
return false;
|
||||
authenticator.updateMemberOf(this);
|
||||
permissions = null;
|
||||
return true;
|
||||
}
|
||||
|
||||
public AuthenticationResult getAuthenticationResult() {
|
||||
return authResult;
|
||||
}
|
||||
|
||||
public void setGroups(final String[] groups) {
|
||||
this.groups = groups;
|
||||
}
|
||||
|
||||
public void setRoles(final String[] roles) {
|
||||
this.roles = roles;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -15,9 +15,16 @@
|
|||
*/
|
||||
package org.codelibs.fess.sso.aad;
|
||||
|
||||
import static org.codelibs.core.stream.StreamUtil.split;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.URI;
|
||||
import java.net.URLEncoder;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.Executors;
|
||||
|
@ -32,8 +39,12 @@ 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.curl.Curl;
|
||||
import org.codelibs.curl.CurlResponse;
|
||||
import org.codelibs.elasticsearch.runner.net.EcrCurl;
|
||||
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.AzureAdCredential.AzureAdUser;
|
||||
import org.codelibs.fess.app.web.base.login.FessLoginAssist.LoginCredentialResolver;
|
||||
import org.codelibs.fess.crawler.Constants;
|
||||
import org.codelibs.fess.exception.SsoLoginException;
|
||||
|
@ -61,15 +72,15 @@ 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_STATE_TTL = "aad.state.ttl";
|
||||
|
||||
protected static final String AZUREAD_AUTHORITY = "azuread.authority";
|
||||
protected static final String AZUREAD_AUTHORITY = "aad.authority";
|
||||
|
||||
protected static final String AZUREAD_TENANT = "azuread.tenant";
|
||||
protected static final String AZUREAD_TENANT = "aad.tenant";
|
||||
|
||||
protected static final String AZUREAD_CLIENT_SECRET = "azuread.client.secret";
|
||||
protected static final String AZUREAD_CLIENT_SECRET = "aad.client.secret";
|
||||
|
||||
protected static final String AZUREAD_CLIENT_ID = "azuread.client.id";
|
||||
protected static final String AZUREAD_CLIENT_ID = "aad.client.id";
|
||||
|
||||
protected static final String STATES = "aadStates";
|
||||
|
||||
|
@ -215,7 +226,7 @@ public class AzureAdAuthenticator implements SsoAuthenticator {
|
|||
}
|
||||
}
|
||||
|
||||
public AuthenticationResult getAccessToken(String refreshToken) {
|
||||
public AuthenticationResult getAccessToken(final String refreshToken) {
|
||||
final String authority = getAuthority() + getTenant() + "/";
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("refreshToken: {}, authority: {}", refreshToken, authority);
|
||||
|
@ -223,15 +234,15 @@ public class AzureAdAuthenticator implements SsoAuthenticator {
|
|||
ExecutorService service = null;
|
||||
try {
|
||||
service = Executors.newFixedThreadPool(1);
|
||||
AuthenticationContext context = new AuthenticationContext(authority, true, service);
|
||||
Future<AuthenticationResult> future =
|
||||
final AuthenticationContext context = new AuthenticationContext(authority, true, service);
|
||||
final Future<AuthenticationResult> future =
|
||||
context.acquireTokenByRefreshToken(refreshToken, new ClientCredential(getClientId(), getClientSecret()), null, null);
|
||||
final AuthenticationResult result = future.get(acquisitionTimeout, TimeUnit.MILLISECONDS);
|
||||
if (result == null) {
|
||||
throw new SsoLoginException("authentication result was null");
|
||||
}
|
||||
return result;
|
||||
} catch (Exception e) {
|
||||
} catch (final Exception e) {
|
||||
throw new SsoLoginException("Failed to get a token.", e);
|
||||
} finally {
|
||||
if (service != null) {
|
||||
|
@ -315,6 +326,74 @@ public class AzureAdAuthenticator implements SsoAuthenticator {
|
|||
return params.containsKey(ERROR) || params.containsKey(ID_TOKEN) || params.containsKey(CODE);
|
||||
}
|
||||
|
||||
public void updateMemberOf(final AzureAdUser user) {
|
||||
final List<String> groupList = new ArrayList<>();
|
||||
final List<String> roleList = new ArrayList<>();
|
||||
groupList.addAll(getDefaultGroupList());
|
||||
roleList.addAll(getDefaultRoleList());
|
||||
try (CurlResponse response =
|
||||
Curl.get("https://graph.microsoft.com/v1.0/me/memberOf")
|
||||
.header("Authorization", "Bearer " + user.getAuthenticationResult().getAccessToken())
|
||||
.header("Accept", "application/json").execute()) {
|
||||
final Map<String, Object> contentMap = response.getContent(EcrCurl.jsonParser);
|
||||
if (contentMap.containsKey("value")) {
|
||||
@SuppressWarnings("unchecked")
|
||||
final List<Map<String, Object>> memberOfList = (List<Map<String, Object>>) contentMap.get("value");
|
||||
for (final Map<String, Object> memberOf : memberOfList) {
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("member: {}", memberOf);
|
||||
}
|
||||
final String id = (String) memberOf.get("id");
|
||||
if (StringUtil.isBlank(id)) {
|
||||
logger.warn("id is empty: {}", memberOf);
|
||||
continue;
|
||||
}
|
||||
String memberType = (String) memberOf.get("@odata.type");
|
||||
if (memberType == null) {
|
||||
logger.warn("@odata.type is null: {}", memberOf);
|
||||
continue;
|
||||
}
|
||||
memberType = memberType.toLowerCase(Locale.ENGLISH);
|
||||
if (memberType.contains("group")) {
|
||||
groupList.add(id);
|
||||
} else if (memberType.contains("role")) {
|
||||
roleList.add(id);
|
||||
} else {
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("unknown @odata.type: {}", memberOf);
|
||||
}
|
||||
groupList.add(id);
|
||||
}
|
||||
}
|
||||
} else if (contentMap.containsKey("error")) {
|
||||
logger.warn("Failed to access groups/roles: {}", contentMap);
|
||||
}
|
||||
} catch (final IOException e) {
|
||||
logger.warn("Failed to access groups/roles in AzureAD.", e);
|
||||
}
|
||||
|
||||
user.setGroups(groupList.toArray(n -> new String[n]));
|
||||
user.setRoles(roleList.toArray(n -> new String[n]));
|
||||
}
|
||||
|
||||
protected List<String> getDefaultGroupList() {
|
||||
final String value = ComponentUtil.getFessConfig().getSystemProperty("aad.default.groups");
|
||||
if (StringUtil.isBlank(value)) {
|
||||
return Collections.emptyList();
|
||||
} else {
|
||||
return split(value, ",").get(stream -> stream.filter(StringUtil::isNotBlank).map(s -> s.trim()).collect(Collectors.toList()));
|
||||
}
|
||||
}
|
||||
|
||||
protected List<String> getDefaultRoleList() {
|
||||
final String value = ComponentUtil.getFessConfig().getSystemProperty("aad.default.roles");
|
||||
if (StringUtil.isBlank(value)) {
|
||||
return Collections.emptyList();
|
||||
} else {
|
||||
return split(value, ",").get(stream -> stream.filter(StringUtil::isNotBlank).map(s -> s.trim()).collect(Collectors.toList()));
|
||||
}
|
||||
}
|
||||
|
||||
protected class StateData {
|
||||
private final String nonce;
|
||||
private final long expiration;
|
||||
|
@ -365,7 +444,7 @@ public class AzureAdAuthenticator implements SsoAuthenticator {
|
|||
});
|
||||
}
|
||||
|
||||
public void setAcquisitionTimeout(long acquisitionTimeout) {
|
||||
public void setAcquisitionTimeout(final long acquisitionTimeout) {
|
||||
this.acquisitionTimeout = acquisitionTimeout;
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue