View Javadoc
1   /*
2    * Copyright 2012-2021 CodeLibs Project and the Others.
3    *
4    * Licensed under the Apache License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    *
8    *     http://www.apache.org/licenses/LICENSE-2.0
9    *
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS,
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
13   * either express or implied. See the License for the specific language
14   * governing permissions and limitations under the License.
15   */
16  package org.codelibs.fess.app.web.base.login;
17  
18  import java.lang.reflect.Method;
19  import java.util.function.Function;
20  
21  import javax.annotation.Resource;
22  
23  import org.codelibs.fess.annotation.Secured;
24  import org.codelibs.fess.app.web.RootAction;
25  import org.codelibs.fess.app.web.base.FessAdminAction;
26  import org.codelibs.fess.app.web.login.LoginAction;
27  import org.codelibs.fess.entity.FessUser;
28  import org.codelibs.fess.es.user.exbhv.UserBhv;
29  import org.codelibs.fess.exception.UserRoleLoginException;
30  import org.codelibs.fess.mylasta.action.FessUserBean;
31  import org.codelibs.fess.mylasta.direction.FessConfig;
32  import org.codelibs.fess.sso.SsoAuthenticator;
33  import org.codelibs.fess.util.ComponentUtil;
34  import org.dbflute.optional.OptionalEntity;
35  import org.dbflute.optional.OptionalThing;
36  import org.lastaflute.core.magic.async.AsyncManager;
37  import org.lastaflute.core.time.TimeManager;
38  import org.lastaflute.web.login.LoginHandlingResource;
39  import org.lastaflute.web.login.PrimaryLoginManager;
40  import org.lastaflute.web.login.TypicalLoginAssist;
41  import org.lastaflute.web.login.credential.LoginCredential;
42  import org.lastaflute.web.login.exception.LoginRequiredException;
43  import org.lastaflute.web.login.option.LoginSpecifiedOption;
44  import org.lastaflute.web.servlet.session.SessionManager;
45  
46  /**
47   * @author jflute
48   * @author shinsuke
49   */
50  public class FessLoginAssist extends TypicalLoginAssist<String, FessUserBean, FessUser> // #change_it also UserBean
51          implements PrimaryLoginManager {
52  
53      // ===================================================================================
54      //                                                                           Attribute
55      //                                                                           =========
56      @Resource
57      private TimeManager timeManager;
58      @Resource
59      private AsyncManager asyncManager;
60      @Resource
61      private SessionManager sessionManager;
62      @Resource
63      private FessConfig fessConfig;
64      @Resource
65      private UserBhv userBhv;
66  
67      // ===================================================================================
68      //                                                                           Find User
69      //                                                                           =========
70      @Override
71      public boolean checkUserLoginable(final LoginCredential credential) {
72          throw new UnsupportedOperationException("checkUserLoginable is not supported.");
73      }
74  
75      @Override
76      protected void checkCredential(final TypicalLoginAssist<String, FessUserBean, FessUser>.CredentialChecker checker) {
77          throw new UnsupportedOperationException("checkCredential is not supported.");
78      }
79  
80      @Override
81      protected OptionalEntity<FessUser> doFindLoginUser(final String username) {
82          return userBhv.selectEntity(cb -> {
83              cb.query().setName_Equal(username);
84          }).map(user -> (FessUser) user);
85      }
86  
87      // ===================================================================================
88      //                                                                       Login Process
89      //                                                                       =============
90      @Override
91      protected FessUserBean createUserBean(final FessUser user) {
92          return new FessUserBean(user);
93      }
94  
95      @Override
96      protected OptionalThing<String> getCookieRememberMeKey() {
97          // example to use remember-me
98          //return OptionalThing.of(fessConfig.getCookieRememberMeFessKey());
99          return OptionalThing.empty();
100     }
101 
102     @Override
103     protected void saveLoginHistory(final FessUser user, final FessUserBean userBean, final LoginSpecifiedOption option) {
104         asyncManager.async(() -> {
105             insertLogin(user);
106         });
107     }
108 
109     protected void insertLogin(final Object member) {
110         // nothing
111     }
112 
113     @Override
114     protected void checkPermission(final LoginHandlingResource resource) throws LoginRequiredException {
115         if (FessAdminAction.class.isAssignableFrom(resource.getActionClass())) {
116             getSavedUserBean().ifPresent(user -> {
117                 if (user.hasRoles(fessConfig.getAuthenticationAdminRolesAsArray())) {
118                     return;
119                 }
120                 final Method executeMethod = resource.getExecuteMethod();
121                 final Secured secured = executeMethod.getAnnotation(Secured.class);
122                 if (secured != null && user.hasRoles(secured.value())) {
123                     return;
124                 }
125                 throw new UserRoleLoginException(RootAction.class);
126             });
127         }
128     }
129 
130     // ===================================================================================
131     //                                                                      Login Resource
132     //                                                                      ==============
133     @Override
134     protected Class<FessUserBean> getUserBeanType() {
135         return FessUserBean.class;
136     }
137 
138     @Override
139     protected Class<?> getLoginActionType() {
140         return LoginAction.class;
141     }
142 
143     @Override
144     protected String toTypedUserId(final String userKey) {
145         return userKey;
146     }
147 
148     // ===================================================================================
149     //                                                                     Login Extension
150     //                                                                      ==============
151 
152     @Override
153     protected void resolveCredential(final CredentialResolver resolver) {
154         resolver.resolve(LocalUserCredential.class, credential -> {
155             final LocalUserCredential userCredential = credential;
156             final String username = userCredential.getUser();
157             final String password = userCredential.getPassword();
158             if (!fessConfig.isAdminUser(username)) {
159                 final OptionalEntity<FessUser> ldapUser = ComponentUtil.getLdapManager().login(username, password);
160                 if (ldapUser.isPresent()) {
161                     return ldapUser;
162                 }
163             }
164             return doFindLoginUser(username, encryptPassword(password));
165         });
166         final LoginCredentialResolver loginResolver = new LoginCredentialResolver(resolver);
167         for (final SsoAuthenticator auth : ComponentUtil.getSsoManager().getAuthenticators()) {
168             auth.resolveCredential(loginResolver);
169         }
170     }
171 
172     public static class LoginCredentialResolver {
173         private final TypicalLoginAssist<String, FessUserBean, FessUser>.CredentialResolver resolver;
174 
175         public LoginCredentialResolver(final CredentialResolver resolver) {
176             this.resolver = resolver;
177         }
178 
179         public <CREDENTIAL extends LoginCredential> void resolve(final Class<CREDENTIAL> credentialType,
180                 final Function<CREDENTIAL, OptionalEntity<FessUser>> oneArgLambda) {
181             resolver.resolve(credentialType, credential -> oneArgLambda.apply(credential));
182         }
183     }
184 
185     protected OptionalEntity<FessUser> doFindLoginUser(final String username, final String cipheredPassword) {
186         return userBhv.selectEntity(cb -> {
187             cb.query().setName_Equal(username);
188             cb.query().setPassword_Equal(cipheredPassword);
189         }).map(user -> (FessUser) user);
190     }
191 }