EnableUserInfoSecurityConfig.java 6.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183
  1. /*
  2. * Copyright 2020-2024 the original author or authors.
  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. * 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,
  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 sample.userinfo;
  17. import java.security.KeyPair;
  18. import java.security.KeyPairGenerator;
  19. import java.security.interfaces.RSAPrivateKey;
  20. import java.security.interfaces.RSAPublicKey;
  21. import java.util.UUID;
  22. import com.nimbusds.jose.jwk.JWKSet;
  23. import com.nimbusds.jose.jwk.RSAKey;
  24. import com.nimbusds.jose.jwk.source.ImmutableJWKSet;
  25. import com.nimbusds.jose.jwk.source.JWKSource;
  26. import com.nimbusds.jose.proc.SecurityContext;
  27. import org.springframework.context.annotation.Bean;
  28. import org.springframework.context.annotation.Configuration;
  29. import org.springframework.core.annotation.Order;
  30. import org.springframework.http.MediaType;
  31. import org.springframework.security.config.Customizer;
  32. import org.springframework.security.config.annotation.web.builders.HttpSecurity;
  33. import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
  34. import org.springframework.security.core.userdetails.User;
  35. import org.springframework.security.core.userdetails.UserDetails;
  36. import org.springframework.security.core.userdetails.UserDetailsService;
  37. import org.springframework.security.oauth2.core.AuthorizationGrantType;
  38. import org.springframework.security.oauth2.core.ClientAuthenticationMethod;
  39. import org.springframework.security.oauth2.core.oidc.OidcScopes;
  40. import org.springframework.security.oauth2.jwt.JwtDecoder;
  41. import org.springframework.security.oauth2.server.authorization.client.InMemoryRegisteredClientRepository;
  42. import org.springframework.security.oauth2.server.authorization.client.RegisteredClient;
  43. import org.springframework.security.oauth2.server.authorization.client.RegisteredClientRepository;
  44. import org.springframework.security.oauth2.server.authorization.config.annotation.web.configuration.OAuth2AuthorizationServerConfiguration;
  45. import org.springframework.security.oauth2.server.authorization.config.annotation.web.configurers.OAuth2AuthorizationServerConfigurer;
  46. import org.springframework.security.oauth2.server.authorization.settings.AuthorizationServerSettings;
  47. import org.springframework.security.oauth2.server.authorization.settings.ClientSettings;
  48. import org.springframework.security.provisioning.InMemoryUserDetailsManager;
  49. import org.springframework.security.web.SecurityFilterChain;
  50. import org.springframework.security.web.authentication.LoginUrlAuthenticationEntryPoint;
  51. import org.springframework.security.web.util.matcher.MediaTypeRequestMatcher;
  52. @Configuration(proxyBeanMethods = false)
  53. @EnableWebSecurity
  54. public class EnableUserInfoSecurityConfig {
  55. @Bean // <1>
  56. @Order(1)
  57. public SecurityFilterChain authorizationServerSecurityFilterChain(HttpSecurity http) throws Exception {
  58. OAuth2AuthorizationServerConfigurer authorizationServerConfigurer =
  59. OAuth2AuthorizationServerConfigurer.authorizationServer();
  60. // @formatter:off
  61. http
  62. .securityMatcher(authorizationServerConfigurer.getEndpointsMatcher())
  63. .with(authorizationServerConfigurer, (authorizationServer) ->
  64. authorizationServer
  65. .oidc(Customizer.withDefaults()) // <2>
  66. )
  67. .authorizeHttpRequests((authorize) ->
  68. authorize
  69. .anyRequest().authenticated()
  70. )
  71. .exceptionHandling((exceptions) -> exceptions
  72. .defaultAuthenticationEntryPointFor(
  73. new LoginUrlAuthenticationEntryPoint("/login"),
  74. new MediaTypeRequestMatcher(MediaType.TEXT_HTML)
  75. )
  76. );
  77. // @formatter:on
  78. return http.build();
  79. }
  80. // @fold:on
  81. @Bean
  82. @Order(2)
  83. public SecurityFilterChain defaultSecurityFilterChain(HttpSecurity http) throws Exception {
  84. // @formatter:off
  85. http
  86. .authorizeHttpRequests((authorize) -> authorize
  87. .anyRequest().authenticated()
  88. )
  89. .formLogin(Customizer.withDefaults());
  90. // @formatter:on
  91. return http.build();
  92. }
  93. // @fold:off
  94. @Bean // <3>
  95. public JwtDecoder jwtDecoder(JWKSource<SecurityContext> jwkSource) {
  96. return OAuth2AuthorizationServerConfiguration.jwtDecoder(jwkSource);
  97. }
  98. // @fold:on
  99. @Bean
  100. public UserDetailsService userDetailsService() {
  101. // @formatter:off
  102. UserDetails userDetails = User.withDefaultPasswordEncoder()
  103. .username("user")
  104. .password("password")
  105. .roles("USER")
  106. .build();
  107. // @formatter:on
  108. return new InMemoryUserDetailsManager(userDetails);
  109. }
  110. @Bean
  111. public RegisteredClientRepository registeredClientRepository() {
  112. // @formatter:off
  113. RegisteredClient registeredClient = RegisteredClient.withId(UUID.randomUUID().toString())
  114. .clientId("messaging-client")
  115. .clientSecret("{noop}secret")
  116. .clientAuthenticationMethod(ClientAuthenticationMethod.CLIENT_SECRET_BASIC)
  117. .authorizationGrantType(AuthorizationGrantType.AUTHORIZATION_CODE)
  118. .authorizationGrantType(AuthorizationGrantType.REFRESH_TOKEN)
  119. .authorizationGrantType(AuthorizationGrantType.CLIENT_CREDENTIALS)
  120. .redirectUri("http://127.0.0.1:8080/login/oauth2/code/messaging-client-oidc")
  121. .redirectUri("http://127.0.0.1:8080/authorized")
  122. .scope(OidcScopes.OPENID)
  123. .scope(OidcScopes.ADDRESS)
  124. .scope(OidcScopes.EMAIL)
  125. .scope(OidcScopes.PHONE)
  126. .scope(OidcScopes.PROFILE)
  127. .scope("message.read")
  128. .scope("message.write")
  129. .clientSettings(ClientSettings.builder().requireAuthorizationConsent(true).build())
  130. .build();
  131. // @formatter:on
  132. return new InMemoryRegisteredClientRepository(registeredClient);
  133. }
  134. @Bean
  135. public JWKSource<SecurityContext> jwkSource() {
  136. KeyPair keyPair = generateRsaKey();
  137. RSAPublicKey publicKey = (RSAPublicKey) keyPair.getPublic();
  138. RSAPrivateKey privateKey = (RSAPrivateKey) keyPair.getPrivate();
  139. // @formatter:off
  140. RSAKey rsaKey = new RSAKey.Builder(publicKey)
  141. .privateKey(privateKey)
  142. .keyID(UUID.randomUUID().toString())
  143. .build();
  144. // @formatter:on
  145. JWKSet jwkSet = new JWKSet(rsaKey);
  146. return new ImmutableJWKSet<>(jwkSet);
  147. }
  148. private static KeyPair generateRsaKey() {
  149. KeyPair keyPair;
  150. try {
  151. KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("RSA");
  152. keyPairGenerator.initialize(2048);
  153. keyPair = keyPairGenerator.generateKeyPair();
  154. }
  155. catch (Exception ex) {
  156. throw new IllegalStateException(ex);
  157. }
  158. return keyPair;
  159. }
  160. @Bean
  161. public AuthorizationServerSettings authorizationServerSettings() {
  162. return AuthorizationServerSettings.builder().build();
  163. }
  164. // @fold:off
  165. }