View Javadoc
1   /*
2    * Copyright 2006-2011 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.exceptions;
14  
15  import com.fasterxml.jackson.core.JsonParser;
16  import com.fasterxml.jackson.core.JsonProcessingException;
17  import com.fasterxml.jackson.core.JsonToken;
18  import com.fasterxml.jackson.databind.DeserializationContext;
19  import com.fasterxml.jackson.databind.deser.std.StdDeserializer;
20  
21  import java.io.IOException;
22  import java.util.HashMap;
23  import java.util.List;
24  import java.util.Map;
25  import java.util.Set;
26  
27  import org.springframework.security.oauth2.common.util.OAuth2Utils;
28  
29  /**
30   * @author Brian Clozel
31   * 
32   */
33  @SuppressWarnings("serial")
34  public class OAuth2ExceptionJackson2Deserializer extends StdDeserializer<OAuth2Exception> {
35  
36  	public OAuth2ExceptionJackson2Deserializer() {
37  		super(OAuth2Exception.class);
38  	}
39  
40  	@Override
41  	public OAuth2Exception deserialize(JsonParser jp, DeserializationContext ctxt) throws IOException,
42  			JsonProcessingException {
43  
44  		JsonToken t = jp.getCurrentToken();
45  		if (t == JsonToken.START_OBJECT) {
46  			t = jp.nextToken();
47  		}
48  		Map<String, Object> errorParams = new HashMap<String, Object>();
49  		for (; t == JsonToken.FIELD_NAME; t = jp.nextToken()) {
50  			// Must point to field name
51  			String fieldName = jp.getCurrentName();
52  			// And then the value...
53  			t = jp.nextToken();
54  			// Note: must handle null explicitly here; value deserializers won't
55  			Object value;
56  			if (t == JsonToken.VALUE_NULL) {
57  				value = null;
58  			}
59  			// Some servers might send back complex content
60  			else if (t == JsonToken.START_ARRAY) {
61  				value = jp.readValueAs(List.class);
62  			}
63  			else if (t == JsonToken.START_OBJECT) {
64  				value = jp.readValueAs(Map.class);
65  			}
66  			else {
67  				value = jp.getText();
68  			}
69  			errorParams.put(fieldName, value);
70  		}
71  
72  		Object errorCode = errorParams.get("error");
73  		String errorMessage = errorParams.get("error_description") != null ? errorParams.get("error_description").toString() : null;
74  		if (errorMessage == null) {
75  			errorMessage = errorCode == null ? "OAuth Error" : errorCode.toString();
76  		}
77  
78  		OAuth2Exception ex;
79  		if ("invalid_client".equals(errorCode)) {
80  			ex = new InvalidClientException(errorMessage);
81  		}
82  		else if ("unauthorized_client".equals(errorCode)) {
83  			ex = new UnauthorizedClientException(errorMessage);
84  		}
85  		else if ("invalid_grant".equals(errorCode)) {
86  			if (errorMessage.toLowerCase().contains("redirect") && errorMessage.toLowerCase().contains("match")) {
87  				ex = new RedirectMismatchException(errorMessage);
88  			}
89  			else {
90  				ex = new InvalidGrantException(errorMessage);
91  			}
92  		}
93  		else if ("invalid_scope".equals(errorCode)) {
94  			ex = new InvalidScopeException(errorMessage);
95  		}
96  		else if ("invalid_token".equals(errorCode)) {
97  			ex = new InvalidTokenException(errorMessage);
98  		}
99  		else if ("invalid_request".equals(errorCode)) {
100 			ex = new InvalidRequestException(errorMessage);
101 		}
102 		else if ("redirect_uri_mismatch".equals(errorCode)) {
103 			ex = new RedirectMismatchException(errorMessage);
104 		}
105 		else if ("unsupported_grant_type".equals(errorCode)) {
106 			ex = new UnsupportedGrantTypeException(errorMessage);
107 		}
108 		else if ("unsupported_response_type".equals(errorCode)) {
109 			ex = new UnsupportedResponseTypeException(errorMessage);
110 		}
111 		else if ("insufficient_scope".equals(errorCode)) {
112 			ex = new InsufficientScopeException(errorMessage, OAuth2Utils.parseParameterList((String) errorParams
113 					.get("scope")));
114 		}
115 		else if ("access_denied".equals(errorCode)) {
116 			ex = new UserDeniedAuthorizationException(errorMessage);
117 		}
118 		else {
119 			ex = new OAuth2Exception(errorMessage);
120 		}
121 
122 		Set<Map.Entry<String, Object>> entries = errorParams.entrySet();
123 		for (Map.Entry<String, Object> entry : entries) {
124 			String key = entry.getKey();
125 			if (!"error".equals(key) && !"error_description".equals(key)) {
126 				Object value = entry.getValue();
127 				ex.addAdditionalInformation(key, value == null ? null : value.toString());
128 			}
129 		}
130 
131 		return ex;
132 
133 	}
134 
135 }