Explorar o código

fix #2056 refresh azure ad token

Shinsuke Sugaya %!s(int64=6) %!d(string=hai) anos
pai
achega
b4029ba2ef

+ 10 - 0
src/main/java/org/codelibs/fess/app/web/base/FessBaseAction.java

@@ -46,6 +46,8 @@ import org.lastaflute.web.servlet.session.SessionManager;
 import org.lastaflute.web.validation.ActionValidator;
 import org.lastaflute.web.validation.LaValidatable;
 import org.lastaflute.web.validation.VaMessenger;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
 
 /**
  * @author jflute
@@ -56,6 +58,8 @@ public abstract class FessBaseAction extends TypicalAction // has several interf
     // ===================================================================================
     //                                                                          Definition
     //                                                                          ==========
+    private static final Logger logger = LoggerFactory.getLogger(FessBaseAction.class);
+
     /** The application type for FESs, e.g. used by access context. */
     protected static final String APP_TYPE = "FES"; // #change_it_first
 
@@ -105,6 +109,12 @@ public abstract class FessBaseAction extends TypicalAction // has several interf
     // you should remove the 'final' if you need to override this
     @Override
     public ActionResponse godHandPrologue(final ActionRuntime runtime) {
+        fessLoginAssist.getSavedUserBean().ifPresent(u -> {
+            boolean result = u.getFessUser().refresh();
+            if (logger.isDebugEnabled()) {
+                logger.debug("refresh user info: {}", result);
+            }
+        });
         return viewHelper.getActionHook().godHandPrologue(runtime, r -> super.godHandPrologue(r));
     }
 

+ 17 - 11
src/main/java/org/codelibs/fess/app/web/base/login/AzureAdCredential.java

@@ -24,6 +24,7 @@ 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;
 import org.codelibs.fess.util.ComponentUtil;
 import org.lastaflute.web.login.credential.LoginCredential;
 
@@ -47,8 +48,8 @@ public class AzureAdCredential implements LoginCredential, FessCredential {
         return "{" + authResult.getUserInfo().getDisplayableId() + "}";
     }
 
-    public User getUser() {
-        return new User(authResult.getUserInfo().getDisplayableId(), getDefaultGroupsAsArray(), getDefaultRolesAsArray());
+    public AzureAdUser getUser() {
+        return new AzureAdUser(authResult, getDefaultGroupsAsArray(), getDefaultRolesAsArray());
     }
 
     protected static String[] getDefaultGroupsAsArray() {
@@ -69,26 +70,26 @@ public class AzureAdCredential implements LoginCredential, FessCredential {
         }
     }
 
-    public static class User implements FessUser {
+    public static class AzureAdUser 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;
+        protected AuthenticationResult authResult;
+
+        public AzureAdUser(final AuthenticationResult authResult, final String[] groups, final String[] roles) {
+            this.authResult = authResult;
             this.groups = groups;
             this.roles = roles;
         }
 
         @Override
         public String getName() {
-            return name;
+            return authResult.getUserInfo().getDisplayableId();
         }
 
         @Override
@@ -106,7 +107,7 @@ public class AzureAdCredential implements LoginCredential, FessCredential {
             if (permissions == null) {
                 final SystemHelper systemHelper = ComponentUtil.getSystemHelper();
                 final Set<String> permissionSet = new HashSet<>();
-                permissionSet.add(systemHelper.getSearchRoleByUser(name));
+                permissionSet.add(systemHelper.getSearchRoleByUser(getName()));
                 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()]);
@@ -115,9 +116,14 @@ public class AzureAdCredential implements LoginCredential, FessCredential {
         }
 
         @Override
-        public boolean isEditable() {
+        public boolean refresh() {
+            if (authResult.getExpiresAfter() < System.currentTimeMillis()) {
+                return false;
+            }
+            final AzureAdAuthenticator authenticator = ComponentUtil.getComponent(AzureAdAuthenticator.class);
+            final String refreshToken = authResult.getRefreshToken();
+            authResult = authenticator.getAccessToken(refreshToken);
             return false;
         }
-
     }
 }

+ 4 - 9
src/main/java/org/codelibs/fess/app/web/base/login/OpenIdConnectCredential.java

@@ -46,8 +46,8 @@ public class OpenIdConnectCredential implements LoginCredential, FessCredential
         return (String) attributes.get("email");
     }
 
-    public User getUser() {
-        return new User(getUserId(), getDefaultGroupsAsArray(), getDefaultRolesAsArray());
+    public OpenIdUser getUser() {
+        return new OpenIdUser(getUserId(), getDefaultGroupsAsArray(), getDefaultRolesAsArray());
     }
 
     protected static String[] getDefaultGroupsAsArray() {
@@ -68,7 +68,7 @@ public class OpenIdConnectCredential implements LoginCredential, FessCredential
         }
     }
 
-    public static class User implements FessUser {
+    public static class OpenIdUser implements FessUser {
 
         private static final long serialVersionUID = 1L;
 
@@ -80,7 +80,7 @@ public class OpenIdConnectCredential implements LoginCredential, FessCredential
 
         protected String[] permissions;
 
-        protected User(final String name, final String[] groups, final String[] roles) {
+        protected OpenIdUser(final String name, final String[] groups, final String[] roles) {
             this.name = name;
             this.groups = groups;
             this.roles = roles;
@@ -114,10 +114,5 @@ public class OpenIdConnectCredential implements LoginCredential, FessCredential
             return permissions;
         }
 
-        @Override
-        public boolean isEditable() {
-            return false;
-        }
-
     }
 }

+ 7 - 1
src/main/java/org/codelibs/fess/entity/FessUser.java

@@ -27,5 +27,11 @@ public interface FessUser extends Serializable {
 
     String[] getPermissions();
 
-    boolean isEditable();
+    default boolean isEditable() {
+        return false;
+    }
+
+    default boolean refresh() {
+        return false;
+    }
 }

+ 36 - 6
src/main/java/org/codelibs/fess/sso/aad/AzureAdAuthenticator.java

@@ -22,6 +22,7 @@ import java.util.Map;
 import java.util.concurrent.ExecutorService;
 import java.util.concurrent.Executors;
 import java.util.concurrent.Future;
+import java.util.concurrent.TimeUnit;
 import java.util.stream.Collectors;
 
 import javax.annotation.PostConstruct;
@@ -84,6 +85,8 @@ public class AzureAdAuthenticator implements SsoAuthenticator {
 
     protected static final String CODE = "code";
 
+    protected long acquisitionTimeout = 30 * 1000L;
+
     @PostConstruct
     public void init() {
         ComponentUtil.getSsoManager().register(this);
@@ -104,10 +107,8 @@ public class AzureAdAuthenticator implements SsoAuthenticator {
                 return null;
             }
 
-            // TODO refresh
-
-                return new ActionResponseCredential(() -> HtmlResponse.fromRedirectPathAsIs(getAuthUrl(request)));
-            }).orElse(null);
+            return new ActionResponseCredential(() -> HtmlResponse.fromRedirectPathAsIs(getAuthUrl(request)));
+        }).orElse(null);
     }
 
     protected String getAuthUrl(final HttpServletRequest request) {
@@ -214,6 +215,31 @@ public class AzureAdAuthenticator implements SsoAuthenticator {
         }
     }
 
+    public AuthenticationResult getAccessToken(String refreshToken) {
+        final String authority = getAuthority() + getTenant() + "/";
+        if (logger.isDebugEnabled()) {
+            logger.debug("refreshToken: {}, authority: {}", refreshToken, authority);
+        }
+        ExecutorService service = null;
+        try {
+            service = Executors.newFixedThreadPool(1);
+            AuthenticationContext context = new AuthenticationContext(authority, true, service);
+            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) {
+            throw new SsoLoginException("Failed to get a token.", e);
+        } finally {
+            if (service != null) {
+                service.shutdown();
+            }
+        }
+    }
+
     protected AuthenticationResult getAccessToken(final AuthorizationCode authorizationCode, final String currentUri) {
         final String authority = getAuthority() + getTenant() + "/";
         final String authCode = authorizationCode.getValue();
@@ -223,11 +249,11 @@ public class AzureAdAuthenticator implements SsoAuthenticator {
         final ClientCredential credential = new ClientCredential(getClientId(), getClientSecret());
         ExecutorService service = null;
         try {
-            service = Executors.newFixedThreadPool(1);// TODO replace with something...
+            service = Executors.newFixedThreadPool(1);
             final AuthenticationContext context = new AuthenticationContext(authority, true, service);
             final Future<AuthenticationResult> future =
                     context.acquireTokenByAuthorizationCode(authCode, new URI(currentUri), credential, null);
-            final AuthenticationResult result = future.get();
+            final AuthenticationResult result = future.get(acquisitionTimeout, TimeUnit.MILLISECONDS);
             if (result == null) {
                 throw new SsoLoginException("authentication result was null");
             }
@@ -338,4 +364,8 @@ public class AzureAdAuthenticator implements SsoAuthenticator {
             return OptionalEntity.of(credential.getUser());
         });
     }
+
+    public void setAcquisitionTimeout(long acquisitionTimeout) {
+        this.acquisitionTimeout = acquisitionTimeout;
+    }
 }