/*
* Copyright 2008-2009 Web Cohesion
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.security.oauth.provider.filter;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.oauth.common.OAuthCodec;
import org.springframework.security.oauth.common.OAuthConsumerParameter;
import org.springframework.security.oauth.common.OAuthProviderParameter;
import org.springframework.security.oauth.provider.ConsumerAuthentication;
import org.springframework.security.oauth.provider.ConsumerDetails;
import org.springframework.security.oauth.provider.InvalidOAuthParametersException;
import org.springframework.security.oauth.provider.token.OAuthProviderToken;
import javax.servlet.FilterChain;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.Map;
/**
* Processing filter for handling a request for an OAuth access token.
*
* @author Ryan Heaton
* @author Andrew McCall
*/
public class AccessTokenProcessingFilter extends OAuthProviderProcessingFilter {
// The OAuth spec doesn't specify a content-type of the response. However, it's NOT
// "application/x-www-form-urlencoded" because the response isn't URL-encoded. Until
// something is specified, we'll assume that it's just "text/plain".
private String responseContentType = "text/plain;charset=utf-8";
private boolean require10a = true;
public AccessTokenProcessingFilter() {
setFilterProcessesUrl("/oauth_access_token");
}
protected OAuthProviderToken createOAuthToken(ConsumerAuthentication authentication) {
return getTokenServices().createAccessToken(authentication.getConsumerCredentials().getToken());
}
@Override
protected void validateAdditionalParameters(ConsumerDetails consumerDetails, Map<String, String> oauthParams) {
super.validateAdditionalParameters(consumerDetails, oauthParams);
String token = oauthParams.get(OAuthConsumerParameter.oauth_token.toString());
if (token == null) {
throw new InvalidOAuthParametersException(messages.getMessage("AccessTokenProcessingFilter.missingToken", "Missing token."));
}
if (isRequire10a()) {
String verifier = oauthParams.get(OAuthConsumerParameter.oauth_verifier.toString());
if (verifier == null) {
throw new InvalidOAuthParametersException(messages.getMessage("AccessTokenProcessingFilter.missingVerifier", "Missing verifier."));
}
OAuthProviderToken requestToken = getTokenServices().getToken(token);
if (!verifier.equals(requestToken.getVerifier())) {
throw new InvalidOAuthParametersException(messages.getMessage("AccessTokenProcessingFilter.missingVerifier", "Invalid verifier."));
}
}
}
protected void onValidSignature(HttpServletRequest request, HttpServletResponse response, FilterChain chain) throws IOException {
//signature is verified; create the token, send the response.
ConsumerAuthentication authentication = (ConsumerAuthentication) SecurityContextHolder.getContext().getAuthentication();
OAuthProviderToken authToken = createOAuthToken(authentication);
if (!authToken.getConsumerKey().equals(authentication.getConsumerDetails().getConsumerKey())) {
throw new IllegalStateException("The consumer key associated with the created auth token is not valid for the authenticated consumer.");
}
String tokenValue = authToken.getValue();
StringBuilder responseValue = new StringBuilder(OAuthProviderParameter.oauth_token.toString())
.append('=')
.append(OAuthCodec.oauthEncode(tokenValue))
.append('&')
.append(OAuthProviderParameter.oauth_token_secret.toString())
.append('=')
.append(OAuthCodec.oauthEncode(authToken.getSecret()));
response.setContentType(getResponseContentType());
response.getWriter().print(responseValue.toString());
response.flushBuffer();
}
@Override
protected void onNewTimestamp() throws AuthenticationException {
throw new InvalidOAuthParametersException(messages.getMessage("AccessTokenProcessingFilter.timestampNotNew", "A new timestamp should not be used in a request for an access token."));
}
/**
* The content type of the response.
*
* @return The content type of the response.
*/
public String getResponseContentType() {
return responseContentType;
}
/**
* The content type of the response.
*
* @param responseContentType The content type of the response.
*/
public void setResponseContentType(String responseContentType) {
this.responseContentType = responseContentType;
}
/**
* Whether to require 1.0a support.
*
* @return Whether to require 1.0a support.
*/
public boolean isRequire10a() {
return require10a;
}
/**
* Whether to require 1.0a support.
*
* @param require10a Whether to require 1.0a support.
*/
public void setRequire10a(boolean require10a) {
this.require10a = require10a;
}
}