1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.springframework.security.oauth2.config.xml;
18
19 import java.util.ArrayList;
20 import java.util.Arrays;
21 import java.util.List;
22
23 import org.springframework.beans.factory.FactoryBean;
24 import org.springframework.beans.factory.config.TypedStringValue;
25 import org.springframework.beans.factory.support.BeanDefinitionBuilder;
26 import org.springframework.beans.factory.xml.AbstractSingleBeanDefinitionParser;
27 import org.springframework.beans.factory.xml.ParserContext;
28 import org.springframework.security.oauth2.client.resource.BaseOAuth2ProtectedResourceDetails;
29 import org.springframework.security.oauth2.client.token.grant.client.ClientCredentialsResourceDetails;
30 import org.springframework.security.oauth2.client.token.grant.code.AuthorizationCodeResourceDetails;
31 import org.springframework.security.oauth2.client.token.grant.implicit.ImplicitResourceDetails;
32 import org.springframework.security.oauth2.client.token.grant.password.ResourceOwnerPasswordResourceDetails;
33 import org.springframework.security.oauth2.common.AuthenticationScheme;
34 import org.springframework.security.oauth2.common.OAuth2AccessToken;
35 import org.springframework.util.StringUtils;
36 import org.w3c.dom.Element;
37
38
39
40
41 public class ResourceBeanDefinitionParser extends AbstractSingleBeanDefinitionParser {
42
43 @Override
44 protected Class<?> getBeanClass(Element element) {
45 String type = element.getAttribute("type");
46 if ("authorization_code".equals(type)) {
47 return AuthorizationCodeResourceDetails.class;
48 }
49 if ("implicit".equals(type)) {
50 return ImplicitResourceDetails.class;
51 }
52 if ("client_credentials".equals(type)) {
53 return ClientCredentialsResourceDetails.class;
54 }
55 if ("password".equals(type)) {
56 return ResourceOwnerPasswordResourceDetails.class;
57 }
58 return BaseOAuth2ProtectedResourceDetails.class;
59 }
60
61 @Override
62 protected void doParse(Element element, ParserContext parserContext, BeanDefinitionBuilder builder) {
63 String id = element.getAttribute("id");
64 if (!StringUtils.hasText(id)) {
65 parserContext.getReaderContext().error("An id must be supplied on a resource element.", element);
66 }
67 builder.addPropertyValue("id", id);
68
69 String type = element.getAttribute("type");
70 if (!StringUtils.hasText(type)) {
71 type = "client_credentials";
72 }
73 builder.addPropertyValue("grantType", type);
74
75 String accessTokenUri = element.getAttribute("access-token-uri");
76 if (!StringUtils.hasText(accessTokenUri) && !"implicit".equals(type)) {
77 parserContext.getReaderContext()
78 .error("An accessTokenUri must be supplied on a resource element of type " + type, element);
79 }
80 builder.addPropertyValue("accessTokenUri", accessTokenUri);
81
82 String clientId = element.getAttribute("client-id");
83 if (!StringUtils.hasText(clientId)) {
84 parserContext.getReaderContext().error("An clientId must be supplied on a resource element", element);
85 }
86 builder.addPropertyValue("clientId", clientId);
87
88 String clientSecret = element.getAttribute("client-secret");
89 if (StringUtils.hasText(clientSecret)) {
90 builder.addPropertyValue("clientSecret", clientSecret);
91 }
92
93 String clientAuthenticationScheme = element.getAttribute("client-authentication-scheme");
94 if (StringUtils.hasText(clientAuthenticationScheme)) {
95 builder.addPropertyValue("clientAuthenticationScheme", clientAuthenticationScheme);
96 }
97
98 String userAuthorizationUri = element.getAttribute("user-authorization-uri");
99 if (StringUtils.hasText(userAuthorizationUri)) {
100 if (needsUserAuthorizationUri(type)) {
101 builder.addPropertyValue("userAuthorizationUri", userAuthorizationUri);
102 } else {
103 parserContext.getReaderContext().error("The " + type + " grant type does not accept an authorization URI", element);
104 }
105 } else {
106 if (needsUserAuthorizationUri(type)) {
107 parserContext.getReaderContext().error("An authorization URI must be supplied for a resource of type " + type, element);
108 }
109 }
110
111 String preEstablishedRedirectUri = element.getAttribute("pre-established-redirect-uri");
112 if (StringUtils.hasText(preEstablishedRedirectUri)) {
113 builder.addPropertyValue("preEstablishedRedirectUri", preEstablishedRedirectUri);
114 }
115
116 String requireImmediateAuthorization = element.getAttribute("require-immediate-authorization");
117 if (StringUtils.hasText(requireImmediateAuthorization)) {
118 builder.addPropertyValue("requireImmediateAuthorization", requireImmediateAuthorization);
119 }
120
121 String useCurrentUri = element.getAttribute("use-current-uri");
122 if (StringUtils.hasText(useCurrentUri)) {
123 builder.addPropertyValue("useCurrentUri", useCurrentUri);
124 }
125
126 String scope = element.getAttribute("scope");
127 if (StringUtils.hasText(scope)) {
128 BeanDefinitionBuilder scopesBuilder = BeanDefinitionBuilder
129 .genericBeanDefinition(StringListFactoryBean.class);
130 scopesBuilder.addConstructorArgValue(new TypedStringValue(scope));
131 builder.addPropertyValue("scope", scopesBuilder.getBeanDefinition());
132 }
133
134 AuthenticationScheme btm = AuthenticationScheme.header;
135 String bearerTokenMethod = element.getAttribute("authentication-scheme");
136 if (StringUtils.hasText(bearerTokenMethod)) {
137 btm = AuthenticationScheme.valueOf(bearerTokenMethod);
138 }
139 builder.addPropertyValue("authenticationScheme", btm);
140
141 String bearerTokenName = element.getAttribute("token-name");
142 if (!StringUtils.hasText(bearerTokenName)) {
143 bearerTokenName = OAuth2AccessToken.ACCESS_TOKEN;
144 }
145 builder.addPropertyValue("tokenName", bearerTokenName);
146
147 if (type.equals("password")) {
148 String[] attributeNames = {"username", "password"};
149 for (String attributeName : attributeNames) {
150 String attribute = element.getAttribute(attributeName);
151 if (StringUtils.hasText(attribute)) {
152 builder.addPropertyValue(attributeName, attribute);
153 } else {
154 parserContext.getReaderContext().error("A " + attributeName + " must be supplied on a resource element of type " + type, element);
155 }
156 }
157 }
158 }
159
160
161
162
163
164
165 public static class StringListFactoryBean implements FactoryBean<List<String>> {
166
167 private final String commaSeparatedList;
168
169 public StringListFactoryBean(String commaSeparatedList) {
170 this.commaSeparatedList = commaSeparatedList;
171 }
172
173 public List<String> getObject() throws Exception {
174 return new ArrayList<String>(Arrays.asList(StringUtils.commaDelimitedListToStringArray(commaSeparatedList)));
175 }
176
177 public Class<?> getObjectType() {
178 return List.class;
179 }
180
181 public boolean isSingleton() {
182 return true;
183 }
184
185 }
186
187 private boolean needsUserAuthorizationUri(String type) {
188 return type.equals("authorization_code") || type.equals("implicit");
189 }
190
191 }