Oauth20AutoConfiguration.java 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381
  1. /*
  2. * Copyright [2020] [MaxKey of copyright http://www.maxkey.top]
  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, either express or implied.
  13. * See the License for the specific language governing permissions and
  14. * limitations under the License.
  15. */
  16. package org.maxkey.autoconfigure;
  17. import java.net.URI;
  18. import java.security.NoSuchAlgorithmException;
  19. import java.security.spec.InvalidKeySpecException;
  20. import javax.servlet.Filter;
  21. import javax.sql.DataSource;
  22. import org.maxkey.authn.AbstractAuthenticationProvider;
  23. import org.maxkey.authn.support.jwt.JwtLoginService;
  24. import org.maxkey.authz.oauth2.provider.ClientDetailsService;
  25. import org.maxkey.authz.oauth2.provider.OAuth2UserDetailsService;
  26. import org.maxkey.authz.oauth2.provider.approval.TokenApprovalStore;
  27. import org.maxkey.authz.oauth2.provider.approval.controller.OAuth20UserApprovalHandler;
  28. import org.maxkey.authz.oauth2.provider.client.ClientDetailsUserDetailsService;
  29. import org.maxkey.authz.oauth2.provider.client.JdbcClientDetailsService;
  30. import org.maxkey.authz.oauth2.provider.code.AuthorizationCodeServices;
  31. import org.maxkey.authz.oauth2.provider.code.InMemoryAuthorizationCodeServices;
  32. import org.maxkey.authz.oauth2.provider.code.RedisAuthorizationCodeServices;
  33. import org.maxkey.authz.oauth2.provider.endpoint.TokenEndpointAuthenticationFilter;
  34. import org.maxkey.authz.oauth2.provider.request.DefaultOAuth2RequestFactory;
  35. import org.maxkey.authz.oauth2.provider.token.TokenStore;
  36. import org.maxkey.authz.oauth2.provider.token.DefaultTokenServices;
  37. import org.maxkey.authz.oauth2.provider.token.store.InMemoryTokenStore;
  38. import org.maxkey.authz.oauth2.provider.token.store.JwtAccessTokenConverter;
  39. import org.maxkey.authz.oauth2.provider.token.store.RedisTokenStore;
  40. import org.maxkey.authz.oidc.idtoken.OIDCIdTokenEnhancer;
  41. import org.maxkey.configuration.oidc.OIDCProviderMetadataDetails;
  42. import org.maxkey.constants.ConstantsPersistence;
  43. import org.maxkey.constants.ConstantsProperties;
  44. import org.maxkey.crypto.jose.keystore.JWKSetKeyStore;
  45. import org.maxkey.crypto.jwt.encryption.service.impl.DefaultJwtEncryptionAndDecryptionService;
  46. import org.maxkey.crypto.jwt.signer.service.impl.DefaultJwtSigningAndValidationService;
  47. import org.maxkey.persistence.db.LoginService;
  48. import org.maxkey.persistence.redis.RedisConnectionFactory;
  49. import org.slf4j.Logger;
  50. import org.slf4j.LoggerFactory;
  51. import org.springframework.beans.factory.InitializingBean;
  52. import org.springframework.beans.factory.annotation.Value;
  53. import org.springframework.boot.web.servlet.FilterRegistrationBean;
  54. import org.springframework.context.annotation.Bean;
  55. import org.springframework.context.annotation.ComponentScan;
  56. import org.springframework.context.annotation.Configuration;
  57. import org.springframework.context.annotation.PropertySource;
  58. import org.springframework.core.io.ClassPathResource;
  59. import org.springframework.jdbc.core.JdbcTemplate;
  60. import org.springframework.security.authentication.ProviderManager;
  61. import org.springframework.security.authentication.dao.DaoAuthenticationProvider;
  62. import org.springframework.security.crypto.password.PasswordEncoder;
  63. import com.nimbusds.jose.JOSEException;
  64. import com.nimbusds.jose.JWEAlgorithm;
  65. @Configuration
  66. @ComponentScan(basePackages = {
  67. "org.maxkey.authz.oauth2.provider.endpoint",
  68. "org.maxkey.authz.oauth2.provider.userinfo.endpoint",
  69. "org.maxkey.authz.oauth2.provider.approval.controller"
  70. })
  71. @PropertySource(ConstantsProperties.applicationPropertySource)
  72. @PropertySource(ConstantsProperties.maxKeyPropertySource)
  73. public class Oauth20AutoConfiguration implements InitializingBean {
  74. private static final Logger _logger = LoggerFactory.getLogger(Oauth20AutoConfiguration.class);
  75. @Bean
  76. public FilterRegistrationBean<Filter> TokenEndpointAuthenticationFilter() {
  77. _logger.debug("TokenEndpointAuthenticationFilter init ");
  78. FilterRegistrationBean<Filter> registration = new FilterRegistrationBean<Filter>();
  79. registration.setFilter(new TokenEndpointAuthenticationFilter());
  80. registration.addUrlPatterns("/oauth/v20/token/*");
  81. registration.setName("TokenEndpointAuthenticationFilter");
  82. registration.setOrder(1);
  83. return registration;
  84. }
  85. /**
  86. * OIDCProviderMetadataDetails.
  87. * Self-issued Provider Metadata
  88. * http://openid.net/specs/openid-connect-core-1_0.html#SelfIssued
  89. */
  90. @Bean(name = "oidcProviderMetadata")
  91. public OIDCProviderMetadataDetails OIDCProviderMetadataDetails(
  92. @Value("${config.oidc.metadata.issuer}")
  93. String issuer,
  94. @Value("${config.oidc.metadata.authorizationEndpoint}")
  95. URI authorizationEndpoint,
  96. @Value("${config.oidc.metadata.tokenEndpoint}")
  97. URI tokenEndpoint,
  98. @Value("${config.oidc.metadata.userinfoEndpoint}")
  99. URI userinfoEndpoint) {
  100. _logger.debug("OIDCProviderMetadataDetails init .");
  101. OIDCProviderMetadataDetails oidcProviderMetadata = new OIDCProviderMetadataDetails();
  102. oidcProviderMetadata.setIssuer(issuer);
  103. oidcProviderMetadata.setAuthorizationEndpoint(authorizationEndpoint);
  104. oidcProviderMetadata.setTokenEndpoint(tokenEndpoint);
  105. oidcProviderMetadata.setUserinfoEndpoint(userinfoEndpoint);
  106. return oidcProviderMetadata;
  107. }
  108. /**
  109. * jwtSetKeyStore.
  110. * @return
  111. */
  112. @Bean(name = "jwkSetKeyStore")
  113. public JWKSetKeyStore jwtSetKeyStore() {
  114. JWKSetKeyStore jwkSetKeyStore = new JWKSetKeyStore();
  115. ClassPathResource classPathResource = new ClassPathResource("/config/keystore.jwks");
  116. jwkSetKeyStore.setLocation(classPathResource);
  117. return jwkSetKeyStore;
  118. }
  119. /**
  120. * jwtSetKeyStore.
  121. * @return
  122. * @throws JOSEException
  123. * @throws InvalidKeySpecException
  124. * @throws NoSuchAlgorithmException
  125. */
  126. @Bean(name = "jwtSignerValidationService")
  127. public DefaultJwtSigningAndValidationService jwtSignerValidationService(
  128. JWKSetKeyStore jwtSetKeyStore)
  129. throws NoSuchAlgorithmException, InvalidKeySpecException, JOSEException {
  130. DefaultJwtSigningAndValidationService jwtSignerValidationService =
  131. new DefaultJwtSigningAndValidationService(jwtSetKeyStore);
  132. jwtSignerValidationService.setDefaultSignerKeyId("maxkey_rsa");
  133. jwtSignerValidationService.setDefaultSigningAlgorithmName("RS256");
  134. return jwtSignerValidationService;
  135. }
  136. /**
  137. * jwtSetKeyStore.
  138. * @return
  139. * @throws JOSEException
  140. * @throws InvalidKeySpecException
  141. * @throws NoSuchAlgorithmException
  142. */
  143. @Bean(name = "jwtEncryptionService")
  144. public DefaultJwtEncryptionAndDecryptionService jwtEncryptionService(
  145. JWKSetKeyStore jwtSetKeyStore)
  146. throws NoSuchAlgorithmException, InvalidKeySpecException, JOSEException {
  147. DefaultJwtEncryptionAndDecryptionService jwtEncryptionService =
  148. new DefaultJwtEncryptionAndDecryptionService(jwtSetKeyStore);
  149. jwtEncryptionService.setDefaultAlgorithm(JWEAlgorithm.RSA1_5);//RSA1_5
  150. jwtEncryptionService.setDefaultDecryptionKeyId("maxkey_rsa");
  151. jwtEncryptionService.setDefaultEncryptionKeyId("maxkey_rsa");
  152. return jwtEncryptionService;
  153. }
  154. /**
  155. * JwtLoginService.
  156. * @return
  157. */
  158. @Bean(name = "jwtLoginService")
  159. public JwtLoginService jwtLoginService(
  160. DefaultJwtSigningAndValidationService jwtSignerValidationService,
  161. OIDCProviderMetadataDetails oidcProviderMetadata,
  162. AbstractAuthenticationProvider authenticationProvider) {
  163. JwtLoginService jwtLoginService = new JwtLoginService(
  164. authenticationProvider,
  165. oidcProviderMetadata,
  166. jwtSignerValidationService
  167. );
  168. return jwtLoginService;
  169. }
  170. /**
  171. * tokenEnhancer.
  172. * @return
  173. */
  174. @Bean(name = "tokenEnhancer")
  175. public OIDCIdTokenEnhancer tokenEnhancer(
  176. DefaultJwtSigningAndValidationService jwtSignerValidationService,
  177. DefaultJwtEncryptionAndDecryptionService jwtEncryptionService,
  178. OIDCProviderMetadataDetails oidcProviderMetadata,
  179. ClientDetailsService oauth20JdbcClientDetailsService) {
  180. OIDCIdTokenEnhancer tokenEnhancer = new OIDCIdTokenEnhancer();
  181. tokenEnhancer.setJwtSignerService(jwtSignerValidationService);
  182. tokenEnhancer.setJwtEnDecryptionService(jwtEncryptionService);
  183. tokenEnhancer.setClientDetailsService(oauth20JdbcClientDetailsService);
  184. tokenEnhancer.setProviderMetadata(oidcProviderMetadata);
  185. return tokenEnhancer;
  186. }
  187. //以上部分为了支持OpenID Connect 1.0
  188. /**
  189. * AuthorizationCodeServices.
  190. * @param persistence int
  191. * @return oauth20AuthorizationCodeServices
  192. */
  193. @Bean(name = "oauth20AuthorizationCodeServices")
  194. public AuthorizationCodeServices oauth20AuthorizationCodeServices(
  195. @Value("${config.server.persistence}") int persistence,
  196. JdbcTemplate jdbcTemplate,
  197. RedisConnectionFactory redisConnFactory) {
  198. AuthorizationCodeServices authorizationCodeServices = null;
  199. if (persistence == ConstantsPersistence.INMEMORY) {
  200. authorizationCodeServices = new InMemoryAuthorizationCodeServices();
  201. _logger.debug("InMemoryAuthorizationCodeServices");
  202. } else if (persistence == ConstantsPersistence.JDBC) {
  203. //authorizationCodeServices = new JdbcAuthorizationCodeServices(jdbcTemplate);
  204. _logger.debug("JdbcAuthorizationCodeServices not support ");
  205. } else if (persistence == ConstantsPersistence.REDIS) {
  206. authorizationCodeServices = new RedisAuthorizationCodeServices(redisConnFactory);
  207. _logger.debug("RedisAuthorizationCodeServices");
  208. }
  209. return authorizationCodeServices;
  210. }
  211. /**
  212. * TokenStore.
  213. * @param persistence int
  214. * @return oauth20TokenStore
  215. */
  216. @Bean(name = "oauth20TokenStore")
  217. public TokenStore oauth20TokenStore(
  218. @Value("${config.server.persistence}") int persistence,
  219. JdbcTemplate jdbcTemplate,
  220. RedisConnectionFactory redisConnFactory) {
  221. TokenStore tokenStore = null;
  222. if (persistence == ConstantsPersistence.INMEMORY) {
  223. tokenStore = new InMemoryTokenStore();
  224. _logger.debug("InMemoryTokenStore");
  225. } else if (persistence == ConstantsPersistence.JDBC) {
  226. //tokenStore = new JdbcTokenStore(jdbcTemplate);
  227. _logger.debug("JdbcTokenStore not support ");
  228. } else if (persistence == ConstantsPersistence.REDIS) {
  229. tokenStore = new RedisTokenStore(redisConnFactory);
  230. _logger.debug("RedisTokenStore");
  231. }
  232. return tokenStore;
  233. }
  234. /**
  235. * jwtAccessTokenConverter.
  236. * @return converter
  237. */
  238. @Bean(name = "converter")
  239. public JwtAccessTokenConverter jwtAccessTokenConverter() {
  240. JwtAccessTokenConverter jwtAccessTokenConverter = new JwtAccessTokenConverter();
  241. return jwtAccessTokenConverter;
  242. }
  243. /**
  244. * clientDetailsService.
  245. * @return oauth20JdbcClientDetailsService
  246. */
  247. @Bean(name = "oauth20JdbcClientDetailsService")
  248. public JdbcClientDetailsService clientDetailsService(DataSource dataSource,PasswordEncoder passwordReciprocal) {
  249. JdbcClientDetailsService clientDetailsService = new JdbcClientDetailsService(dataSource);
  250. clientDetailsService.setPasswordEncoder(passwordReciprocal);
  251. return clientDetailsService;
  252. }
  253. /**
  254. * clientDetailsUserDetailsService.
  255. * @return oauth20TokenServices
  256. */
  257. @Bean(name = "oauth20TokenServices")
  258. public DefaultTokenServices DefaultTokenServices(
  259. JdbcClientDetailsService oauth20JdbcClientDetailsService,
  260. TokenStore oauth20TokenStore,
  261. OIDCIdTokenEnhancer tokenEnhancer) {
  262. DefaultTokenServices tokenServices = new DefaultTokenServices();
  263. tokenServices.setClientDetailsService(oauth20JdbcClientDetailsService);
  264. tokenServices.setTokenEnhancer(tokenEnhancer);
  265. tokenServices.setTokenStore(oauth20TokenStore);
  266. tokenServices.setSupportRefreshToken(true);
  267. return tokenServices;
  268. }
  269. /**
  270. * TokenApprovalStore.
  271. * @return oauth20ApprovalStore
  272. */
  273. @Bean(name = "oauth20ApprovalStore")
  274. public TokenApprovalStore tokenApprovalStore(
  275. TokenStore oauth20TokenStore) {
  276. TokenApprovalStore tokenApprovalStore = new TokenApprovalStore();
  277. tokenApprovalStore.setTokenStore(oauth20TokenStore);
  278. return tokenApprovalStore;
  279. }
  280. /**
  281. * OAuth2RequestFactory.
  282. * @return oAuth2RequestFactory
  283. */
  284. @Bean(name = "oAuth2RequestFactory")
  285. public DefaultOAuth2RequestFactory oauth2RequestFactory(
  286. JdbcClientDetailsService oauth20JdbcClientDetailsService) {
  287. DefaultOAuth2RequestFactory oauth2RequestFactory =
  288. new DefaultOAuth2RequestFactory(oauth20JdbcClientDetailsService);
  289. return oauth2RequestFactory;
  290. }
  291. /**
  292. * OAuth20UserApprovalHandler.
  293. * @return oauth20UserApprovalHandler
  294. */
  295. @Bean(name = "oauth20UserApprovalHandler")
  296. public OAuth20UserApprovalHandler oauth20UserApprovalHandler(
  297. JdbcClientDetailsService oauth20JdbcClientDetailsService,
  298. DefaultOAuth2RequestFactory oAuth2RequestFactory,
  299. TokenApprovalStore oauth20ApprovalStore
  300. ) {
  301. OAuth20UserApprovalHandler userApprovalHandler = new OAuth20UserApprovalHandler();
  302. userApprovalHandler.setApprovalStore(oauth20ApprovalStore);
  303. userApprovalHandler.setRequestFactory(oAuth2RequestFactory);
  304. userApprovalHandler.setClientDetailsService(oauth20JdbcClientDetailsService);
  305. return userApprovalHandler;
  306. }
  307. /**
  308. * ProviderManager.
  309. * @return oauth20UserAuthenticationManager
  310. */
  311. @Bean(name = "oauth20UserAuthenticationManager")
  312. public ProviderManager oauth20UserAuthenticationManager(
  313. PasswordEncoder passwordEncoder,
  314. LoginService loginService
  315. ) {
  316. OAuth2UserDetailsService userDetailsService =new OAuth2UserDetailsService();
  317. userDetailsService.setLoginService(loginService);
  318. DaoAuthenticationProvider daoAuthenticationProvider= new DaoAuthenticationProvider();
  319. daoAuthenticationProvider.setPasswordEncoder(passwordEncoder);
  320. daoAuthenticationProvider.setUserDetailsService(userDetailsService);
  321. ProviderManager authenticationManager = new ProviderManager(daoAuthenticationProvider);
  322. return authenticationManager;
  323. }
  324. /**
  325. * ProviderManager.
  326. * @return oauth20ClientAuthenticationManager
  327. */
  328. @Bean(name = "oauth20ClientAuthenticationManager")
  329. public ProviderManager oauth20ClientAuthenticationManager(
  330. JdbcClientDetailsService oauth20JdbcClientDetailsService,
  331. PasswordEncoder passwordReciprocal
  332. ) {
  333. ClientDetailsUserDetailsService cientDetailsUserDetailsService =
  334. new ClientDetailsUserDetailsService(oauth20JdbcClientDetailsService);
  335. DaoAuthenticationProvider daoAuthenticationProvider= new DaoAuthenticationProvider();
  336. daoAuthenticationProvider.setPasswordEncoder(passwordReciprocal);
  337. daoAuthenticationProvider.setUserDetailsService(cientDetailsUserDetailsService);
  338. ProviderManager authenticationManager = new ProviderManager(daoAuthenticationProvider);
  339. return authenticationManager;
  340. }
  341. @Override
  342. public void afterPropertiesSet() throws Exception {
  343. // TODO Auto-generated method stub
  344. }
  345. }