1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package org.springframework.security.oauth2.config.annotation.web.configurers;
17
18 import java.util.ArrayList;
19 import java.util.Collections;
20 import java.util.List;
21
22 import javax.servlet.Filter;
23
24 import org.springframework.http.MediaType;
25 import org.springframework.security.authentication.AuthenticationManager;
26 import org.springframework.security.config.annotation.SecurityConfigurerAdapter;
27 import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
28 import org.springframework.security.config.annotation.web.builders.HttpSecurity;
29 import org.springframework.security.config.annotation.web.configurers.ExceptionHandlingConfigurer;
30 import org.springframework.security.crypto.password.PasswordEncoder;
31 import org.springframework.security.oauth2.provider.ClientDetailsService;
32 import org.springframework.security.oauth2.provider.client.ClientCredentialsTokenEndpointFilter;
33 import org.springframework.security.oauth2.provider.client.ClientDetailsUserDetailsService;
34 import org.springframework.security.oauth2.provider.endpoint.FrameworkEndpointHandlerMapping;
35 import org.springframework.security.oauth2.provider.error.OAuth2AccessDeniedHandler;
36 import org.springframework.security.oauth2.provider.error.OAuth2AuthenticationEntryPoint;
37 import org.springframework.security.web.AuthenticationEntryPoint;
38 import org.springframework.security.web.DefaultSecurityFilterChain;
39 import org.springframework.security.web.access.AccessDeniedHandler;
40 import org.springframework.security.web.authentication.www.BasicAuthenticationEntryPoint;
41 import org.springframework.security.web.authentication.www.BasicAuthenticationFilter;
42 import org.springframework.security.web.context.NullSecurityContextRepository;
43 import org.springframework.security.web.util.matcher.MediaTypeRequestMatcher;
44 import org.springframework.util.Assert;
45 import org.springframework.util.StringUtils;
46 import org.springframework.web.accept.ContentNegotiationStrategy;
47 import org.springframework.web.accept.HeaderContentNegotiationStrategy;
48
49
50
51
52
53
54
55 public final class AuthorizationServerSecurityConfigurer extends
56 SecurityConfigurerAdapter<DefaultSecurityFilterChain, HttpSecurity> {
57
58 private AuthenticationEntryPoint authenticationEntryPoint;
59
60 private AccessDeniedHandler accessDeniedHandler = new OAuth2AccessDeniedHandler();
61
62 private PasswordEncoder passwordEncoder;
63
64 private String realm = "oauth2/client";
65
66 private boolean allowFormAuthenticationForClients = false;
67
68 private String tokenKeyAccess = "denyAll()";
69
70 private String checkTokenAccess = "denyAll()";
71
72 private boolean sslOnly = false;
73
74
75
76
77
78 private List<Filter> tokenEndpointAuthenticationFilters = new ArrayList<Filter>();
79
80 public AuthorizationServerSecurityConfigurer sslOnly() {
81 this.sslOnly = true;
82 return this;
83 }
84
85 public AuthorizationServerSecurityConfigurer allowFormAuthenticationForClients() {
86 this.allowFormAuthenticationForClients = true;
87 return this;
88 }
89
90 public AuthorizationServerSecurityConfigurer realm(String realm) {
91 this.realm = realm;
92 return this;
93 }
94
95 public AuthorizationServerSecurityConfigurer passwordEncoder(PasswordEncoder passwordEncoder) {
96 this.passwordEncoder = passwordEncoder;
97 return this;
98 }
99
100 public AuthorizationServerSecurityConfigurer authenticationEntryPoint(
101 AuthenticationEntryPoint authenticationEntryPoint) {
102 this.authenticationEntryPoint = authenticationEntryPoint;
103 return this;
104 }
105
106 public AuthorizationServerSecurityConfigurer accessDeniedHandler(AccessDeniedHandler accessDeniedHandler) {
107 this.accessDeniedHandler = accessDeniedHandler;
108 return this;
109 }
110
111 public AuthorizationServerSecurityConfigurer tokenKeyAccess(String tokenKeyAccess) {
112 this.tokenKeyAccess = tokenKeyAccess;
113 return this;
114 }
115
116 public AuthorizationServerSecurityConfigurer checkTokenAccess(String checkTokenAccess) {
117 this.checkTokenAccess = checkTokenAccess;
118 return this;
119 }
120
121 public String getTokenKeyAccess() {
122 return tokenKeyAccess;
123 }
124
125 public String getCheckTokenAccess() {
126 return checkTokenAccess;
127 }
128
129 @Override
130 public void init(HttpSecurity http) throws Exception {
131
132 registerDefaultAuthenticationEntryPoint(http);
133 if (passwordEncoder != null) {
134 ClientDetailsUserDetailsService clientDetailsUserDetailsService = new ClientDetailsUserDetailsService(clientDetailsService());
135 clientDetailsUserDetailsService.setPasswordEncoder(passwordEncoder());
136 http.getSharedObject(AuthenticationManagerBuilder.class)
137 .userDetailsService(clientDetailsUserDetailsService)
138 .passwordEncoder(passwordEncoder());
139 }
140 else {
141 http.userDetailsService(new ClientDetailsUserDetailsService(clientDetailsService()));
142 }
143 http.securityContext().securityContextRepository(new NullSecurityContextRepository()).and().csrf().disable()
144 .httpBasic().authenticationEntryPoint(this.authenticationEntryPoint).realmName(realm);
145 if (sslOnly) {
146 http.requiresChannel().anyRequest().requiresSecure();
147 }
148 }
149
150 private PasswordEncoder passwordEncoder() {
151 return new PasswordEncoder() {
152
153 @Override
154 public boolean matches(CharSequence rawPassword, String encodedPassword) {
155 return StringUtils.hasText(encodedPassword) ? passwordEncoder.matches(rawPassword, encodedPassword)
156 : true;
157 }
158
159 @Override
160 public String encode(CharSequence rawPassword) {
161 return passwordEncoder.encode(rawPassword);
162 }
163 };
164 }
165
166 @SuppressWarnings("unchecked")
167 private void registerDefaultAuthenticationEntryPoint(HttpSecurity http) {
168 ExceptionHandlingConfigurer<HttpSecurity> exceptionHandling = http
169 .getConfigurer(ExceptionHandlingConfigurer.class);
170 if (exceptionHandling == null) {
171 return;
172 }
173 if (authenticationEntryPoint==null) {
174 BasicAuthenticationEntryPoint basicEntryPoint = new BasicAuthenticationEntryPoint();
175 basicEntryPoint.setRealmName(realm);
176 authenticationEntryPoint = basicEntryPoint;
177 }
178 ContentNegotiationStrategy contentNegotiationStrategy = http.getSharedObject(ContentNegotiationStrategy.class);
179 if (contentNegotiationStrategy == null) {
180 contentNegotiationStrategy = new HeaderContentNegotiationStrategy();
181 }
182 MediaTypeRequestMatcher preferredMatcher = new MediaTypeRequestMatcher(contentNegotiationStrategy,
183 MediaType.APPLICATION_ATOM_XML, MediaType.APPLICATION_FORM_URLENCODED, MediaType.APPLICATION_JSON,
184 MediaType.APPLICATION_OCTET_STREAM, MediaType.APPLICATION_XML, MediaType.MULTIPART_FORM_DATA,
185 MediaType.TEXT_XML);
186 preferredMatcher.setIgnoredMediaTypes(Collections.singleton(MediaType.ALL));
187 exceptionHandling.defaultAuthenticationEntryPointFor(postProcess(authenticationEntryPoint), preferredMatcher);
188 }
189
190 @Override
191 public void configure(HttpSecurity http) throws Exception {
192
193
194 frameworkEndpointHandlerMapping();
195 if (allowFormAuthenticationForClients) {
196 clientCredentialsTokenEndpointFilter(http);
197 }
198
199 for (Filter filter : tokenEndpointAuthenticationFilters) {
200 http.addFilterBefore(filter, BasicAuthenticationFilter.class);
201 }
202
203 http.exceptionHandling().accessDeniedHandler(accessDeniedHandler);
204 }
205
206 private ClientCredentialsTokenEndpointFilter clientCredentialsTokenEndpointFilter(HttpSecurity http) {
207 ClientCredentialsTokenEndpointFilter clientCredentialsTokenEndpointFilter = new ClientCredentialsTokenEndpointFilter(
208 frameworkEndpointHandlerMapping().getServletPath("/oauth/token"));
209 clientCredentialsTokenEndpointFilter
210 .setAuthenticationManager(http.getSharedObject(AuthenticationManager.class));
211 OAuth2AuthenticationEntryPoint authenticationEntryPoint = new OAuth2AuthenticationEntryPoint();
212 authenticationEntryPoint.setTypeName("Form");
213 authenticationEntryPoint.setRealmName(realm);
214 clientCredentialsTokenEndpointFilter.setAuthenticationEntryPoint(authenticationEntryPoint);
215 clientCredentialsTokenEndpointFilter = postProcess(clientCredentialsTokenEndpointFilter);
216 http.addFilterBefore(clientCredentialsTokenEndpointFilter, BasicAuthenticationFilter.class);
217 return clientCredentialsTokenEndpointFilter;
218 }
219
220 private ClientDetailsService clientDetailsService() {
221 return getBuilder().getSharedObject(ClientDetailsService.class);
222 }
223
224 private FrameworkEndpointHandlerMapping frameworkEndpointHandlerMapping() {
225 return getBuilder().getSharedObject(FrameworkEndpointHandlerMapping.class);
226 }
227
228
229
230
231
232
233
234 public void addTokenEndpointAuthenticationFilter(Filter filter) {
235 this.tokenEndpointAuthenticationFilters.add(filter);
236 }
237
238
239
240
241
242
243
244 public void tokenEndpointAuthenticationFilters(List<Filter> filters) {
245 Assert.notNull(filters, "Custom authentication filter list must not be null");
246 this.tokenEndpointAuthenticationFilters = new ArrayList<Filter>(filters);
247 }
248 }