View Javadoc
1   /*
2    * Copyright 2006-2010 the original author or authors.
3    *
4    * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
5    * the License. You may obtain a copy of the License at
6    *
7    * https://www.apache.org/licenses/LICENSE-2.0
8    *
9    * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
10   * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
11   * specific language governing permissions and limitations under the License.
12   */
13  package org.springframework.security.oauth2.common;
14  
15  
16  import java.io.IOException;
17  import java.util.Date;
18  import java.util.LinkedHashMap;
19  import java.util.Map;
20  import java.util.Set;
21  import java.util.TreeSet;
22  
23  import org.springframework.security.oauth2.common.util.OAuth2Utils;
24  
25  import com.fasterxml.jackson.core.JsonParseException;
26  import com.fasterxml.jackson.core.JsonParser;
27  import com.fasterxml.jackson.core.JsonProcessingException;
28  import com.fasterxml.jackson.core.JsonToken;
29  import com.fasterxml.jackson.databind.DeserializationContext;
30  import com.fasterxml.jackson.databind.deser.std.StdDeserializer;
31  
32  /**
33   * <p>
34   * Provides the ability to deserialize JSON response into an {@link org.springframework.security.oauth2.common.OAuth2AccessToken} with jackson2 by implementing
35   * {@link com.fasterxml.jackson.databind.JsonDeserializer}.
36   * </p>
37   * <p>
38   * The expected format of the access token is defined by <a
39   * href="https://tools.ietf.org/html/draft-ietf-oauth-v2-22#section-5.1">Successful Response</a>.
40   * </p>
41   *
42   * @author Rob Winch
43   * @author Brian Clozel
44   * @see org.springframework.security.oauth2.common.OAuth2AccessTokenJackson2Serializer
45   */
46  @SuppressWarnings("serial")
47  public final class OAuth2AccessTokenJackson2Deserializer extends StdDeserializer<OAuth2AccessToken> {
48  
49  	public OAuth2AccessTokenJackson2Deserializer() {
50  		super(OAuth2AccessToken.class);
51  	}
52  
53  	@Override
54  	public OAuth2AccessToken deserialize(JsonParser jp, DeserializationContext ctxt) throws IOException,
55  			JsonProcessingException {
56  
57  		String tokenValue = null;
58  		String tokenType = null;
59  		String refreshToken = null;
60  		Long expiresIn = null;
61  		Set<String> scope = null;
62  		Map<String, Object> additionalInformation = new LinkedHashMap<String, Object>();
63  
64  		// TODO What should occur if a parameter exists twice
65  		while (jp.nextToken() != JsonToken.END_OBJECT) {
66  			String name = jp.getCurrentName();
67  			jp.nextToken();
68  			if (OAuth2AccessToken.ACCESS_TOKEN.equals(name)) {
69  				tokenValue = jp.getText();
70  			}
71  			else if (OAuth2AccessToken.TOKEN_TYPE.equals(name)) {
72  				tokenType = jp.getText();
73  			}
74  			else if (OAuth2AccessToken.REFRESH_TOKEN.equals(name)) {
75  				refreshToken = jp.getText();
76  			}
77  			else if (OAuth2AccessToken.EXPIRES_IN.equals(name)) {
78  				try {
79  					expiresIn = jp.getLongValue();
80  				} catch (JsonParseException e) {
81  					expiresIn = Long.valueOf(jp.getText());
82  				}
83  			}
84  			else if (OAuth2AccessToken.SCOPE.equals(name)) {
85  				scope = parseScope(jp);
86  			} else {
87  				additionalInformation.put(name, jp.readValueAs(Object.class));
88  			}
89  		}
90  
91  		// TODO What should occur if a required parameter (tokenValue or tokenType) is missing?
92  
93  		DefaultOAuth2AccessToken accessToken = new DefaultOAuth2AccessToken(tokenValue);
94  		accessToken.setTokenType(tokenType);
95  		if (expiresIn != null) {
96  			accessToken.setExpiration(new Date(System.currentTimeMillis() + (expiresIn * 1000)));
97  		}
98  		if (refreshToken != null) {
99  			accessToken.setRefreshToken(new DefaultOAuth2RefreshToken(refreshToken));
100 		}
101 		accessToken.setScope(scope);
102 		accessToken.setAdditionalInformation(additionalInformation);
103 
104 		return accessToken;
105 	}
106 
107 	private Set<String> parseScope(JsonParser jp) throws JsonParseException, IOException {
108 		Set<String> scope;
109 		if (jp.getCurrentToken() == JsonToken.START_ARRAY) {
110 			scope = new TreeSet<String>();
111 			while (jp.nextToken() != JsonToken.END_ARRAY) {
112 				scope.add(jp.getValueAsString());
113 			}
114 		} else {
115 			String text = jp.getText();
116 			scope = OAuth2Utils.parseParameterList(text);
117 		}
118 		return scope;
119 	}
120 }