fix #2122 retrieve parent groups
This commit is contained in:
parent
892bc7d10e
commit
ec0eec9af2
1 changed files with 110 additions and 4 deletions
|
@ -26,6 +26,7 @@ import java.util.HashMap;
|
|||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.Executors;
|
||||
import java.util.concurrent.Future;
|
||||
|
@ -38,7 +39,9 @@ import javax.servlet.http.HttpSession;
|
|||
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.codelibs.core.lang.StringUtil;
|
||||
import org.codelibs.core.misc.Pair;
|
||||
import org.codelibs.core.net.UuidUtil;
|
||||
import org.codelibs.core.stream.StreamUtil;
|
||||
import org.codelibs.curl.Curl;
|
||||
import org.codelibs.curl.CurlResponse;
|
||||
import org.codelibs.elasticsearch.runner.net.EcrCurl;
|
||||
|
@ -50,6 +53,7 @@ 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.codelibs.fess.util.DocumentUtil;
|
||||
import org.dbflute.optional.OptionalEntity;
|
||||
import org.lastaflute.web.login.credential.LoginCredential;
|
||||
import org.lastaflute.web.response.HtmlResponse;
|
||||
|
@ -57,6 +61,8 @@ import org.lastaflute.web.util.LaRequestUtil;
|
|||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import com.google.common.cache.Cache;
|
||||
import com.google.common.cache.CacheBuilder;
|
||||
import com.microsoft.aad.adal4j.AuthenticationContext;
|
||||
import com.microsoft.aad.adal4j.AuthenticationResult;
|
||||
import com.microsoft.aad.adal4j.ClientCredential;
|
||||
|
@ -100,9 +106,14 @@ public class AzureAdAuthenticator implements SsoAuthenticator {
|
|||
|
||||
protected long acquisitionTimeout = 30 * 1000L;
|
||||
|
||||
protected Cache<String, Pair<String[], String[]>> groupCache;
|
||||
|
||||
protected long groupCacheExpiry = 10 * 60L;
|
||||
|
||||
@PostConstruct
|
||||
public void init() {
|
||||
ComponentUtil.getSsoManager().register(this);
|
||||
groupCache = CacheBuilder.newBuilder().expireAfterWrite(groupCacheExpiry, TimeUnit.SECONDS).build();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -333,11 +344,22 @@ public class AzureAdAuthenticator implements SsoAuthenticator {
|
|||
final List<String> roleList = new ArrayList<>();
|
||||
groupList.addAll(getDefaultGroupList());
|
||||
roleList.addAll(getDefaultRoleList());
|
||||
processMemberOf(user, groupList, roleList, "https://graph.microsoft.com/v1.0/me/memberOf");
|
||||
user.setGroups(groupList.stream().distinct().toArray(n -> new String[n]));
|
||||
user.setRoles(roleList.stream().distinct().toArray(n -> new String[n]));
|
||||
}
|
||||
|
||||
protected void processMemberOf(final AzureAdUser user, final List<String> groupList, final List<String> roleList, final String url) {
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("url: {}", url);
|
||||
}
|
||||
try (CurlResponse response =
|
||||
Curl.get("https://graph.microsoft.com/v1.0/me/memberOf")
|
||||
.header("Authorization", "Bearer " + user.getAuthenticationResult().getAccessToken())
|
||||
Curl.get(url).header("Authorization", "Bearer " + user.getAuthenticationResult().getAccessToken())
|
||||
.header("Accept", "application/json").execute()) {
|
||||
final Map<String, Object> contentMap = response.getContent(EcrCurl.jsonParser);
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("response: {}", contentMap);
|
||||
}
|
||||
if (contentMap.containsKey("value")) {
|
||||
@SuppressWarnings("unchecked")
|
||||
final List<Map<String, Object>> memberOfList = (List<Map<String, Object>>) contentMap.get("value");
|
||||
|
@ -363,6 +385,7 @@ public class AzureAdAuthenticator implements SsoAuthenticator {
|
|||
}
|
||||
groupList.add(id);
|
||||
}
|
||||
processParentGroup(user, groupList, roleList, id);
|
||||
} else {
|
||||
logger.warn("id is empty: {}", memberOf);
|
||||
}
|
||||
|
@ -382,15 +405,94 @@ public class AzureAdAuthenticator implements SsoAuthenticator {
|
|||
logger.debug("mail is empty: {}", memberOf);
|
||||
}
|
||||
}
|
||||
final String nextLink = (String) contentMap.get("@odata.nextLink");
|
||||
if (StringUtil.isNotBlank(nextLink)) {
|
||||
processMemberOf(user, groupList, roleList, nextLink);
|
||||
}
|
||||
} 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 void processParentGroup(final AzureAdUser user, final List<String> groupList, final List<String> roleList, final String id) {
|
||||
final Pair<String[], String[]> groupsAndRoles = getParentGroup(user, id);
|
||||
StreamUtil.stream(groupsAndRoles.getFirst()).of(stream -> stream.forEach(groupList::add));
|
||||
StreamUtil.stream(groupsAndRoles.getSecond()).of(stream -> stream.forEach(roleList::add));
|
||||
}
|
||||
|
||||
protected Pair<String[], String[]> getParentGroup(final AzureAdUser user, final String id) {
|
||||
try {
|
||||
return groupCache.get(
|
||||
id,
|
||||
() -> {
|
||||
final List<String> groupList = new ArrayList<>();
|
||||
final List<String> roleList = new ArrayList<>();
|
||||
final String url = "https://graph.microsoft.com/v1.0/groups/" + id + "/getMemberGroups";
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("url: {}", url);
|
||||
}
|
||||
try (CurlResponse response =
|
||||
Curl.post(url).header("Authorization", "Bearer " + user.getAuthenticationResult().getAccessToken())
|
||||
.header("Accept", "application/json").header("Content-type", "application/json")
|
||||
.body("{\"securityEnabledOnly\":false}").execute()) {
|
||||
final Map<String, Object> contentMap = response.getContent(EcrCurl.jsonParser);
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("response: {}", contentMap);
|
||||
}
|
||||
if (contentMap.containsKey("value")) {
|
||||
final String[] values = DocumentUtil.getValue(contentMap, "value", String[].class);
|
||||
if (values != null) {
|
||||
for (final String value : values) {
|
||||
processGroup(user, groupList, roleList, value);
|
||||
if (!groupList.contains(value) && !roleList.contains(value)) {
|
||||
final Pair<String[], String[]> groupsAndRoles = getParentGroup(user, value);
|
||||
StreamUtil.stream(groupsAndRoles.getFirst()).of(stream1 -> stream1.forEach(groupList::add));
|
||||
StreamUtil.stream(groupsAndRoles.getSecond()).of(stream2 -> stream2.forEach(roleList::add));
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if (contentMap.containsKey("error")) {
|
||||
logger.warn("Failed to access parent groups: {}", contentMap);
|
||||
}
|
||||
} catch (final IOException e) {
|
||||
logger.warn("Failed to access groups/roles in AzureAD.", e);
|
||||
}
|
||||
return new Pair<>(groupList.stream().distinct().toArray(n1 -> new String[n1]), roleList.stream().distinct()
|
||||
.toArray(n2 -> new String[n2]));
|
||||
});
|
||||
} catch (final ExecutionException e) {
|
||||
logger.warn("Failed to process a group cache.", e);
|
||||
return new Pair<>(StringUtil.EMPTY_STRINGS, StringUtil.EMPTY_STRINGS);
|
||||
}
|
||||
}
|
||||
|
||||
protected void processGroup(final AzureAdUser user, final List<String> groupList, final List<String> roleList, final String id) {
|
||||
final String url = "https://graph.microsoft.com/v1.0/groups/" + id;
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("url: {}", url);
|
||||
}
|
||||
try (CurlResponse response =
|
||||
Curl.get(url).header("Authorization", "Bearer " + user.getAuthenticationResult().getAccessToken())
|
||||
.header("Accept", "application/json").execute()) {
|
||||
final Map<String, Object> contentMap = response.getContent(EcrCurl.jsonParser);
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("response: {}", contentMap);
|
||||
}
|
||||
groupList.add(id);
|
||||
if (contentMap.containsKey("error")) {
|
||||
logger.warn("Failed to access parent groups: {}", contentMap);
|
||||
} else {
|
||||
final String mail = (String) contentMap.get("mail");
|
||||
if (StringUtil.isNotBlank(mail)) {
|
||||
groupList.add(mail);
|
||||
}
|
||||
}
|
||||
} catch (final IOException e) {
|
||||
logger.warn("Failed to access groups/roles in AzureAD.", e);
|
||||
}
|
||||
}
|
||||
|
||||
protected List<String> getDefaultGroupList() {
|
||||
|
@ -472,4 +574,8 @@ public class AzureAdAuthenticator implements SsoAuthenticator {
|
|||
public void setAcquisitionTimeout(final long acquisitionTimeout) {
|
||||
this.acquisitionTimeout = acquisitionTimeout;
|
||||
}
|
||||
|
||||
public void setGroupCacheExpiry(long groupCacheExpiry) {
|
||||
this.groupCacheExpiry = groupCacheExpiry;
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue