1   /*
2    * Copyright 2018 LINE Corporation
3    *
4    * LINE Corporation licenses this file to you under the Apache License,
5    * version 2.0 (the "License"); you may not use this file except in compliance
6    * with the License. You may obtain a copy of the License at:
7    *
8    *   https://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, WITHOUT
12   * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13   * License for the specific language governing permissions and limitations
14   * under the License.
15   */
16  package com.linecorp.centraldogma.server.auth.shiro;
17  
18  import static java.util.Objects.requireNonNull;
19  
20  import java.time.Duration;
21  import java.util.concurrent.CompletableFuture;
22  import java.util.function.Function;
23  import java.util.function.Supplier;
24  
25  import org.apache.shiro.config.Ini;
26  import org.apache.shiro.config.IniSecurityManagerFactory;
27  import org.apache.shiro.mgt.DefaultSecurityManager;
28  import org.apache.shiro.mgt.SecurityManager;
29  import org.apache.shiro.session.mgt.DefaultSessionManager;
30  import org.apache.shiro.util.Factory;
31  
32  import com.linecorp.armeria.server.HttpService;
33  import com.linecorp.centraldogma.server.auth.AuthConfig;
34  import com.linecorp.centraldogma.server.auth.AuthProvider;
35  import com.linecorp.centraldogma.server.auth.Session;
36  
37  /**
38   * Apache Shiro based {@link AuthProvider} implementation.
39   */
40  public final class ShiroAuthProvider implements AuthProvider {
41  
42      private final HttpService loginApiService;
43      private final HttpService logoutApiService;
44  
45      ShiroAuthProvider(AuthConfig authConfig,
46                        Ini config,
47                        Supplier<String> sessionIdGenerator,
48                        Function<Session, CompletableFuture<Void>> loginSessionPropagator,
49                        Function<String, CompletableFuture<Void>> logoutSessionPropagator) {
50          requireNonNull(authConfig, "authConfig");
51          requireNonNull(config, "config");
52          requireNonNull(sessionIdGenerator, "sessionIdGenerator");
53          requireNonNull(loginSessionPropagator, "loginSessionPropagator");
54          requireNonNull(logoutSessionPropagator, "logoutSessionPropagator");
55  
56          final SecurityManager securityManager = createSecurityManager(config, sessionIdGenerator);
57          final Duration sessionValidDuration = Duration.ofMillis(authConfig.sessionTimeoutMillis());
58  
59          loginApiService = new LoginService(securityManager, authConfig.loginNameNormalizer(),
60                                             loginSessionPropagator, sessionValidDuration);
61          logoutApiService = new LogoutService(securityManager, logoutSessionPropagator);
62      }
63  
64      private static SecurityManager createSecurityManager(Ini config, Supplier<String> sessionIdGenerator) {
65          final Factory<SecurityManager> factory = new IniSecurityManagerFactory(config) {
66              @Override
67              protected SecurityManager createDefaultInstance() {
68                  final DefaultSessionManager sessionManager = new DefaultSessionManager();
69                  // This session DAO is required to cache the session in a very short time, especially while
70                  // logging in to the Central Dogma server. After that, the general session manager provided
71                  // by Central Dogma server will be working for the session management.
72                  sessionManager.setSessionDAO(new LimitedMemorySessionDAO(sessionIdGenerator,
73                                                                           64, Duration.ofHours(1)));
74  
75                  final DefaultSecurityManager securityManager = new DefaultSecurityManager();
76                  securityManager.setSessionManager(sessionManager);
77  
78                  return securityManager;
79              }
80          };
81          return factory.getInstance();
82      }
83  
84      @Override
85      public HttpService loginApiService() {
86          return loginApiService;
87      }
88  
89      @Override
90      public HttpService logoutApiService() {
91          return logoutApiService;
92      }
93  }