1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.bremersee.security.authentication;
18
19 import lombok.extern.slf4j.Slf4j;
20 import org.bremersee.context.MessageSourceProperties;
21 import org.springframework.beans.factory.ObjectProvider;
22 import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
23 import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
24 import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
25 import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
26 import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication;
27 import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication.Type;
28 import org.springframework.boot.context.event.ApplicationReadyEvent;
29 import org.springframework.boot.context.properties.EnableConfigurationProperties;
30 import org.springframework.boot.web.client.RestTemplateBuilder;
31 import org.springframework.context.annotation.Bean;
32 import org.springframework.context.annotation.Conditional;
33 import org.springframework.context.annotation.Configuration;
34 import org.springframework.context.event.EventListener;
35 import org.springframework.security.oauth2.jwt.JwtDecoder;
36 import org.springframework.util.Assert;
37 import org.springframework.util.ClassUtils;
38
39
40
41
42
43
44 @ConditionalOnWebApplication(type = Type.SERVLET)
45 @ConditionalOnClass({
46 RestTemplateBuilder.class,
47 JsonPathJwtConverter.class,
48 RestTemplateAccessTokenRetriever.class
49 })
50 @Configuration
51 @EnableConfigurationProperties({AuthProperties.class, MessageSourceProperties.class})
52 @Slf4j
53 public class JwtSupportAutoConfiguration {
54
55 private final AuthProperties properties;
56
57
58
59
60
61
62 public JwtSupportAutoConfiguration(
63 AuthProperties properties) {
64 this.properties = properties;
65 }
66
67
68
69
70 @EventListener(ApplicationReadyEvent.class)
71 public void init() {
72 log.info("\n"
73 + "*********************************************************************************\n"
74 + "* {}\n"
75 + "*********************************************************************************\n"
76 + "* rolesJsonPath = {}\n"
77 + "* rolesValueList = {}\n"
78 + "* rolesValueSeparator = {}\n"
79 + "* rolePrefix = {}\n"
80 + "* nameJsonPath = {}\n"
81 + "*********************************************************************************",
82 ClassUtils.getUserClass(getClass()).getSimpleName(),
83 properties.getRolesJsonPath(),
84 properties.isRolesValueList(),
85 properties.getRolesValueSeparator(),
86 properties.getRolePrefix(),
87 properties.getNameJsonPath());
88 }
89
90
91
92
93
94
95
96 @ConditionalOnMissingBean
97 @Bean
98 public AuthenticationDetails authenticationDetails(
99 MessageSourceProperties messageSourceProperties) {
100 return new JsonPathJwtAuthenticationDetails(
101 messageSourceProperties.defaultLocale(),
102 messageSourceProperties.defaultTimeZone(),
103 properties.getPreferredLanguageJsonPath(),
104 properties.getPreferredTimeZoneJsonPath());
105 }
106
107
108
109
110
111
112 @ConditionalOnProperty(
113 prefix = "spring.security.oauth2.resourceserver.jwt",
114 name = "jwk-set-uri")
115 @ConditionalOnMissingBean
116 @Bean
117 @SuppressWarnings("DuplicatedCode")
118 public JsonPathJwtConverter jsonPathJwtConverter() {
119 log.info("Creating application {} ...", JsonPathJwtConverter.class.getSimpleName());
120 JsonPathJwtConverter converter = new JsonPathJwtConverter();
121 converter.setNameJsonPath(properties.getNameJsonPath());
122 converter.setRolePrefix(properties.getRolePrefix());
123 converter.setRolesJsonPath(properties.getRolesJsonPath());
124 converter.setRolesValueList(properties.isRolesValueList());
125 converter.setRolesValueSeparator(properties.getRolesValueSeparator());
126 return converter;
127 }
128
129
130
131
132
133
134
135
136 @Conditional(JwtSupportCondition.class)
137 @ConditionalOnMissingBean
138 @Bean
139 public RestTemplateAccessTokenRetriever restTemplateAccessTokenRetriever(
140 ObjectProvider<RestTemplateBuilder> restTemplateBuilder,
141 ObjectProvider<AccessTokenCache> accessTokenCache) {
142
143 AccessTokenCache cache = accessTokenCache.getIfAvailable();
144 log.info("Creating common {} with cache {} ...",
145 RestTemplateAccessTokenRetriever.class.getSimpleName(), cache);
146 Assert.notNull(
147 restTemplateBuilder.getIfAvailable(),
148 "Rest template builder must be present.");
149 return new RestTemplateAccessTokenRetriever(
150 restTemplateBuilder.getIfAvailable().build(),
151 cache);
152 }
153
154
155
156
157
158
159
160
161
162 @ConditionalOnProperty(
163 prefix = "bremersee.auth.password-flow",
164 name = {
165 "token-endpoint",
166 "client-id",
167 "client-secret"
168 })
169 @ConditionalOnBean(JsonPathJwtConverter.class)
170 @ConditionalOnMissingBean(PasswordFlowAuthenticationManager.class)
171 @Bean
172 public PasswordFlowAuthenticationManager passwordFlowAuthenticationManager(
173 ObjectProvider<JwtDecoder> jwtDecoder,
174 JsonPathJwtConverter jwtConverter,
175 RestTemplateAccessTokenRetriever tokenRetriever) {
176
177 log.info("Creating application {} ...",
178 PasswordFlowAuthenticationManager.class.getSimpleName());
179 Assert.notNull(
180 jwtDecoder.getIfAvailable(),
181 "Jwt decoder must be present.");
182 return new PasswordFlowAuthenticationManager(
183 properties.getPasswordFlow(),
184 jwtDecoder.getIfAvailable(),
185 jwtConverter,
186 tokenRetriever);
187 }
188
189 }