1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package org.codelibs.fess.app.web.base.login;
17
18 import static org.codelibs.core.stream.StreamUtil.stream;
19
20 import java.util.HashSet;
21 import java.util.Set;
22
23 import org.apache.logging.log4j.LogManager;
24 import org.apache.logging.log4j.Logger;
25 import org.codelibs.core.lang.StringUtil;
26 import org.codelibs.fess.entity.FessUser;
27 import org.codelibs.fess.helper.SystemHelper;
28 import org.codelibs.fess.sso.entraid.EntraIdAuthenticator;
29 import org.codelibs.fess.util.ComponentUtil;
30 import org.lastaflute.web.login.credential.LoginCredential;
31
32 import com.microsoft.aad.msal4j.IAccount;
33 import com.microsoft.aad.msal4j.IAuthenticationResult;
34
35
36
37
38
39 public class EntraIdCredential implements LoginCredential, FessCredential {
40
41 private static final Logger logger = LogManager.getLogger(EntraIdCredential.class);
42
43 private final IAuthenticationResult authResult;
44
45
46
47
48
49 public EntraIdCredential(final IAuthenticationResult authResult) {
50 this.authResult = authResult;
51 }
52
53 @Override
54 public String getUserId() {
55 return authResult.account().username();
56 }
57
58 @Override
59 public String toString() {
60 return "{" + authResult.account().username() + "}";
61 }
62
63
64
65
66
67 public EntraIdUser getUser() {
68 return new EntraIdUser(authResult);
69 }
70
71
72
73
74 public static class EntraIdUser implements FessUser {
75 private static final long serialVersionUID = 1L;
76
77
78 protected volatile String[] groups;
79
80
81 protected volatile String[] roles;
82
83
84 protected volatile String[] permissions;
85
86
87 protected IAuthenticationResult authResult;
88
89
90
91
92
93 public EntraIdUser(final IAuthenticationResult authResult) {
94 this.authResult = authResult;
95 final EntraIdAuthenticator authenticator = ComponentUtil.getComponent(EntraIdAuthenticator.class);
96 authenticator.updateMemberOf(this);
97 }
98
99 @Override
100 public String getName() {
101 return authResult.account().username();
102 }
103
104 @Override
105 public String[] getRoleNames() {
106 return roles;
107 }
108
109 @Override
110 public String[] getGroupNames() {
111 return groups;
112 }
113
114 @Override
115 public String[] getPermissions() {
116 if (permissions == null) {
117 final SystemHelper systemHelper = ComponentUtil.getSystemHelper();
118 final Set<String> permissionSet = new HashSet<>();
119 final IAccount account = authResult.account();
120 final String homeAccountId = account.homeAccountId();
121 final String username = account.username();
122 if (logger.isDebugEnabled()) {
123 logger.debug("homeAccountId={}, username={}", homeAccountId, username);
124 }
125 permissionSet.add(systemHelper.getSearchRoleByUser(homeAccountId));
126 permissionSet.add(systemHelper.getSearchRoleByUser(username));
127 if (ComponentUtil.getFessConfig().isEntraIdUseDomainServices() && username.indexOf('@') >= 0) {
128 final String[] values = username.split("@");
129 if (values.length > 1) {
130 permissionSet.add(systemHelper.getSearchRoleByUser(values[0]));
131 }
132 }
133 stream(groups).of(stream -> stream.forEach(s -> permissionSet.add(systemHelper.getSearchRoleByGroup(s))));
134 stream(roles).of(stream -> stream.forEach(s -> permissionSet.add(systemHelper.getSearchRoleByRole(s))));
135 permissions = permissionSet.stream().filter(StringUtil::isNotBlank).distinct().toArray(n -> new String[n]);
136 }
137 return permissions;
138 }
139
140 @Override
141 public boolean refresh() {
142
143
144 final long tokenExpiryTime = authResult.expiresOnDate().getTime();
145 final long currentTime = ComponentUtil.getSystemHelper().getCurrentTimeAsLong();
146 if (tokenExpiryTime < currentTime) {
147 if (logger.isDebugEnabled()) {
148 logger.debug("Token expired: expiryTime={}, currentTime={}", tokenExpiryTime, currentTime);
149 }
150 return false;
151 }
152
153 try {
154 final EntraIdAuthenticator authenticator = ComponentUtil.getComponent(EntraIdAuthenticator.class);
155 final IAuthenticationResult newResult = authenticator.refreshTokenSilently(this);
156 if (newResult != null) {
157 authResult = newResult;
158 authenticator.updateMemberOf(this);
159 permissions = null;
160 if (logger.isDebugEnabled()) {
161 logger.debug("Token refreshed successfully via silent authentication");
162 }
163 return true;
164 }
165 } catch (final Exception e) {
166 if (logger.isDebugEnabled()) {
167 logger.debug("Silent token refresh failed: {}", e.getMessage());
168 }
169 }
170
171
172 return true;
173 }
174
175
176
177
178
179 public IAuthenticationResult getAuthenticationResult() {
180 return authResult;
181 }
182
183
184
185
186
187 public synchronized void setGroups(final String[] groups) {
188 this.groups = groups;
189 }
190
191
192
193
194
195 public synchronized void setRoles(final String[] roles) {
196 this.roles = roles;
197 }
198
199
200
201
202
203 public void resetPermissions() {
204 this.permissions = null;
205 }
206 }
207 }