1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.springframework.security.oauth2.client.filter;
18
19 import java.io.IOException;
20
21 import javax.servlet.FilterChain;
22 import javax.servlet.ServletException;
23 import javax.servlet.http.HttpServletRequest;
24 import javax.servlet.http.HttpServletResponse;
25
26 import org.springframework.context.ApplicationEvent;
27 import org.springframework.context.ApplicationEventPublisher;
28 import org.springframework.security.authentication.AuthenticationDetailsSource;
29 import org.springframework.security.authentication.AuthenticationManager;
30 import org.springframework.security.authentication.BadCredentialsException;
31 import org.springframework.security.authentication.event.AuthenticationSuccessEvent;
32 import org.springframework.security.core.Authentication;
33 import org.springframework.security.core.AuthenticationException;
34 import org.springframework.security.oauth2.client.OAuth2RestOperations;
35 import org.springframework.security.oauth2.client.http.AccessTokenRequiredException;
36 import org.springframework.security.oauth2.common.OAuth2AccessToken;
37 import org.springframework.security.oauth2.common.exceptions.InvalidTokenException;
38 import org.springframework.security.oauth2.common.exceptions.OAuth2Exception;
39 import org.springframework.security.oauth2.provider.OAuth2Authentication;
40 import org.springframework.security.oauth2.provider.authentication.OAuth2AuthenticationDetails;
41 import org.springframework.security.oauth2.provider.authentication.OAuth2AuthenticationDetailsSource;
42 import org.springframework.security.oauth2.provider.token.ResourceServerTokenServices;
43 import org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter;
44 import org.springframework.util.Assert;
45
46
47
48
49
50
51
52
53 public class OAuth2ClientAuthenticationProcessingFilter extends AbstractAuthenticationProcessingFilter {
54
55 public OAuth2RestOperations restTemplate;
56
57 private ResourceServerTokenServices tokenServices;
58
59 private AuthenticationDetailsSource<HttpServletRequest, ?> authenticationDetailsSource = new OAuth2AuthenticationDetailsSource();
60
61 private ApplicationEventPublisher eventPublisher;
62
63
64
65
66
67
68 public void setTokenServices(ResourceServerTokenServices tokenServices) {
69 this.tokenServices = tokenServices;
70 }
71
72
73
74
75
76
77 public void setRestTemplate(OAuth2RestOperations restTemplate) {
78 this.restTemplate = restTemplate;
79 }
80
81 @Override
82 public void setApplicationEventPublisher(ApplicationEventPublisher eventPublisher) {
83 this.eventPublisher = eventPublisher;
84 super.setApplicationEventPublisher(eventPublisher);
85 }
86
87 public OAuth2ClientAuthenticationProcessingFilter(String defaultFilterProcessesUrl) {
88 super(defaultFilterProcessesUrl);
89 setAuthenticationManager(new NoopAuthenticationManager());
90 setAuthenticationDetailsSource(authenticationDetailsSource);
91 }
92
93 @Override
94 public void afterPropertiesSet() {
95 Assert.state(restTemplate != null, "Supply a rest-template");
96 super.afterPropertiesSet();
97 }
98
99 @Override
100 public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response)
101 throws AuthenticationException, IOException, ServletException {
102
103 OAuth2AccessToken accessToken;
104 try {
105 accessToken = restTemplate.getAccessToken();
106 } catch (OAuth2Exception e) {
107 BadCredentialsException bad = new BadCredentialsException("Could not obtain access token", e);
108 publish(new OAuth2AuthenticationFailureEvent(bad));
109 throw bad;
110 }
111 try {
112 OAuth2Authentication result = tokenServices.loadAuthentication(accessToken.getValue());
113 if (authenticationDetailsSource!=null) {
114 request.setAttribute(OAuth2AuthenticationDetails.ACCESS_TOKEN_VALUE, accessToken.getValue());
115 request.setAttribute(OAuth2AuthenticationDetails.ACCESS_TOKEN_TYPE, accessToken.getTokenType());
116 result.setDetails(authenticationDetailsSource.buildDetails(request));
117 }
118 publish(new AuthenticationSuccessEvent(result));
119 return result;
120 }
121 catch (InvalidTokenException e) {
122 BadCredentialsException bad = new BadCredentialsException("Could not obtain user details from token", e);
123 publish(new OAuth2AuthenticationFailureEvent(bad));
124 throw bad;
125 }
126
127 }
128
129 private void publish(ApplicationEvent event) {
130 if (eventPublisher!=null) {
131 eventPublisher.publishEvent(event);
132 }
133 }
134
135 @Override
136 protected void successfulAuthentication(HttpServletRequest request, HttpServletResponse response,
137 FilterChain chain, Authentication authResult) throws IOException, ServletException {
138 super.successfulAuthentication(request, response, chain, authResult);
139
140 restTemplate.getAccessToken();
141 }
142
143 @Override
144 protected void unsuccessfulAuthentication(HttpServletRequest request, HttpServletResponse response,
145 AuthenticationException failed) throws IOException, ServletException {
146 if (failed instanceof AccessTokenRequiredException) {
147
148 throw failed;
149 }
150 else {
151
152 super.unsuccessfulAuthentication(request, response, failed);
153 }
154 }
155
156 private static class NoopAuthenticationManager implements AuthenticationManager {
157
158 @Override
159 public Authentication authenticate(Authentication authentication)
160 throws AuthenticationException {
161 throw new UnsupportedOperationException("No authentication should be done with this AuthenticationManager");
162 }
163
164 }
165
166 }