View Javadoc
1   /*
2    * Copyright 2008-2009 Web Cohesion
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  
17  package org.springframework.security.oauth.provider.filter;
18  
19  import org.springframework.security.core.AuthenticationException;
20  import org.springframework.security.core.context.SecurityContextHolder;
21  import org.springframework.security.oauth.common.OAuthCodec;
22  import org.springframework.security.oauth.common.OAuthConsumerParameter;
23  import org.springframework.security.oauth.common.OAuthProviderParameter;
24  import org.springframework.security.oauth.provider.ConsumerAuthentication;
25  import org.springframework.security.oauth.provider.ConsumerDetails;
26  import org.springframework.security.oauth.provider.InvalidOAuthParametersException;
27  import org.springframework.security.oauth.provider.token.OAuthProviderToken;
28  
29  import javax.servlet.FilterChain;
30  import javax.servlet.http.HttpServletRequest;
31  import javax.servlet.http.HttpServletResponse;
32  import java.io.IOException;
33  import java.util.Map;
34  
35  /**
36   * Processing filter for handling a request for an OAuth access token.
37   *
38   * @author Ryan Heaton
39   * @author Andrew McCall
40   */
41  public class AccessTokenProcessingFilter extends OAuthProviderProcessingFilter {
42  
43    // The OAuth spec doesn't specify a content-type of the response.  However, it's NOT
44    // "application/x-www-form-urlencoded" because the response isn't URL-encoded. Until
45    // something is specified, we'll assume that it's just "text/plain".
46    private String responseContentType = "text/plain;charset=utf-8";
47  
48    private boolean require10a = true;
49  
50    public AccessTokenProcessingFilter() {
51      setFilterProcessesUrl("/oauth_access_token");
52    }
53  
54    protected OAuthProviderToken createOAuthToken(ConsumerAuthentication authentication) {
55      return getTokenServices().createAccessToken(authentication.getConsumerCredentials().getToken());
56    }
57  
58    @Override
59    protected void validateAdditionalParameters(ConsumerDetails consumerDetails, Map<String, String> oauthParams) {
60      super.validateAdditionalParameters(consumerDetails, oauthParams);
61  
62      String token = oauthParams.get(OAuthConsumerParameter.oauth_token.toString());
63      if (token == null) {
64        throw new InvalidOAuthParametersException(messages.getMessage("AccessTokenProcessingFilter.missingToken", "Missing token."));
65      }
66  
67      if (isRequire10a()) {
68        String verifier = oauthParams.get(OAuthConsumerParameter.oauth_verifier.toString());
69        if (verifier == null) {
70          throw new InvalidOAuthParametersException(messages.getMessage("AccessTokenProcessingFilter.missingVerifier", "Missing verifier."));
71        }
72        OAuthProviderToken requestToken = getTokenServices().getToken(token);
73        if (!verifier.equals(requestToken.getVerifier())) {
74          throw new InvalidOAuthParametersException(messages.getMessage("AccessTokenProcessingFilter.missingVerifier", "Invalid verifier."));
75        }
76      }
77    }
78  
79    protected void onValidSignature(HttpServletRequest request, HttpServletResponse response, FilterChain chain) throws IOException {
80      //signature is verified; create the token, send the response.
81      ConsumerAuthenticationringframework/security/oauth/provider/ConsumerAuthentication.html#ConsumerAuthentication">ConsumerAuthentication authentication = (ConsumerAuthentication) SecurityContextHolder.getContext().getAuthentication();
82      OAuthProviderToken authToken = createOAuthToken(authentication);
83      if (!authToken.getConsumerKey().equals(authentication.getConsumerDetails().getConsumerKey())) {
84        throw new IllegalStateException("The consumer key associated with the created auth token is not valid for the authenticated consumer.");
85      }
86  
87      String tokenValue = authToken.getValue();
88  
89      StringBuilder responseValue = new StringBuilder(OAuthProviderParameter.oauth_token.toString())
90        .append('=')
91        .append(OAuthCodec.oauthEncode(tokenValue))
92        .append('&')
93        .append(OAuthProviderParameter.oauth_token_secret.toString())
94        .append('=')
95        .append(OAuthCodec.oauthEncode(authToken.getSecret()));
96      response.setContentType(getResponseContentType());
97      response.getWriter().print(responseValue.toString());
98      response.flushBuffer();
99    }
100 
101   @Override
102   protected void onNewTimestamp() throws AuthenticationException {
103     throw new InvalidOAuthParametersException(messages.getMessage("AccessTokenProcessingFilter.timestampNotNew", "A new timestamp should not be used in a request for an access token."));
104   }
105 
106   /**
107    * The content type of the response.
108    *
109    * @return The content type of the response.
110    */
111   public String getResponseContentType() {
112     return responseContentType;
113   }
114 
115   /**
116    * The content type of the response.
117    *
118    * @param responseContentType The content type of the response.
119    */
120   public void setResponseContentType(String responseContentType) {
121     this.responseContentType = responseContentType;
122   }
123 
124   /**
125    * Whether to require 1.0a support.
126    *
127    * @return Whether to require 1.0a support.
128    */
129   public boolean isRequire10a() {
130     return require10a;
131   }
132 
133   /**
134    * Whether to require 1.0a support.
135    *
136    * @param require10a Whether to require 1.0a support.
137    */
138   public void setRequire10a(boolean require10a) {
139     this.require10a = require10a;
140   }
141 }