View Javadoc
1   /*
2    * Copyright 2002-2013 the original author or authors.
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  package org.springframework.security.oauth2.config.annotation.builders;
17  
18  import java.util.ArrayList;
19  import java.util.Collection;
20  import java.util.HashSet;
21  import java.util.LinkedHashMap;
22  import java.util.LinkedHashSet;
23  import java.util.List;
24  import java.util.Map;
25  import java.util.Set;
26  
27  import org.springframework.security.config.annotation.SecurityBuilder;
28  import org.springframework.security.config.annotation.SecurityConfigurerAdapter;
29  import org.springframework.security.core.authority.AuthorityUtils;
30  import org.springframework.security.oauth2.provider.ClientDetails;
31  import org.springframework.security.oauth2.provider.ClientDetailsService;
32  import org.springframework.security.oauth2.provider.client.BaseClientDetails;
33  
34  /**
35   * Builder for OAuth2 client details service. Can be used to construct either an in-memory or a JDBC implementation of
36   * the {@link ClientDetailsService} and populate it with data.
37   * 
38   * @author Dave Syer
39   * 
40   */
41  public class ClientDetailsServiceBuilder<B extends ClientDetailsServiceBuilder<B>> extends
42  		SecurityConfigurerAdapter<ClientDetailsService, B> implements SecurityBuilder<ClientDetailsService> {
43  
44  	private List<ClientBuilder> clientBuilders = new ArrayList<ClientBuilder>();
45  
46  	public InMemoryClientDetailsServiceBuilder inMemory() throws Exception {
47  		return new InMemoryClientDetailsServiceBuilder();
48  	}
49  
50  	public JdbcClientDetailsServiceBuilder jdbc() throws Exception {
51  		return new JdbcClientDetailsServiceBuilder();
52  	}
53  
54  	@SuppressWarnings("rawtypes")
55  	public ClientDetailsServiceBuilder<?> clients(final ClientDetailsService clientDetailsService) throws Exception {
56  		return new ClientDetailsServiceBuilder() {
57  			@Override
58  			public ClientDetailsService build() throws Exception {
59  				return clientDetailsService;
60  			}
61  		};
62  	}
63  
64  	public ClientBuilder withClient(String clientId) {
65  		ClientBuilder clientBuilder = new ClientBuilder(clientId);
66  		this.clientBuilders.add(clientBuilder);
67  		return clientBuilder;
68  	}
69  
70  	@Override
71  	public ClientDetailsService build() throws Exception {
72  		for (ClientBuilder clientDetailsBldr : clientBuilders) {
73  			addClient(clientDetailsBldr.clientId, clientDetailsBldr.build());
74  		}
75  		return performBuild();
76  	}
77  
78  	protected void addClient(String clientId, ClientDetails build) {
79  	}
80  
81  	protected ClientDetailsService performBuild() {
82  		throw new UnsupportedOperationException("Cannot build client services (maybe use inMemory() or jdbc()).");
83  	}
84  
85  	public final class ClientBuilder {
86  		private final String clientId;
87  
88  		private Collection<String> authorizedGrantTypes = new LinkedHashSet<String>();
89  
90  		private Collection<String> authorities = new LinkedHashSet<String>();
91  
92  		private Integer accessTokenValiditySeconds;
93  
94  		private Integer refreshTokenValiditySeconds;
95  
96  		private Collection<String> scopes = new LinkedHashSet<String>();
97  
98  		private Collection<String> autoApproveScopes = new HashSet<String>();
99  
100 		private String secret;
101 
102 		private Set<String> registeredRedirectUris = new HashSet<String>();
103 
104 		private Set<String> resourceIds = new HashSet<String>();
105 
106 		private boolean autoApprove;
107 
108 		private Map<String, Object> additionalInformation = new LinkedHashMap<String, Object>();
109 
110 		private ClientDetails build() {
111 			BaseClientDetails result = new BaseClientDetails();
112 			result.setClientId(clientId);
113 			result.setAuthorizedGrantTypes(authorizedGrantTypes);
114 			result.setAccessTokenValiditySeconds(accessTokenValiditySeconds);
115 			result.setRefreshTokenValiditySeconds(refreshTokenValiditySeconds);
116 			result.setRegisteredRedirectUri(registeredRedirectUris);
117 			result.setClientSecret(secret);
118 			result.setScope(scopes);
119 			result.setAuthorities(AuthorityUtils.createAuthorityList(authorities.toArray(new String[authorities.size()])));
120 			result.setResourceIds(resourceIds);
121 			result.setAdditionalInformation(additionalInformation);
122 			if (autoApprove) {
123 				result.setAutoApproveScopes(scopes);
124 			}
125 			else {
126 				result.setAutoApproveScopes(autoApproveScopes);
127 			}
128 			return result;
129 		}
130 
131 		public ClientBuilder resourceIds(String... resourceIds) {
132 			for (String resourceId : resourceIds) {
133 				this.resourceIds.add(resourceId);
134 			}
135 			return this;
136 		}
137 
138 		public ClientBuilder redirectUris(String... registeredRedirectUris) {
139 			for (String redirectUri : registeredRedirectUris) {
140 				this.registeredRedirectUris.add(redirectUri);
141 			}
142 			return this;
143 		}
144 
145 		public ClientBuilder authorizedGrantTypes(String... authorizedGrantTypes) {
146 			for (String grant : authorizedGrantTypes) {
147 				this.authorizedGrantTypes.add(grant);
148 			}
149 			return this;
150 		}
151 
152 		public ClientBuilder accessTokenValiditySeconds(int accessTokenValiditySeconds) {
153 			this.accessTokenValiditySeconds = accessTokenValiditySeconds;
154 			return this;
155 		}
156 
157 		public ClientBuilder refreshTokenValiditySeconds(int refreshTokenValiditySeconds) {
158 			this.refreshTokenValiditySeconds = refreshTokenValiditySeconds;
159 			return this;
160 		}
161 
162 		public ClientBuilder secret(String secret) {
163 			this.secret = secret;
164 			return this;
165 		}
166 
167 		public ClientBuilder scopes(String... scopes) {
168 			for (String scope : scopes) {
169 				this.scopes.add(scope);
170 			}
171 			return this;
172 		}
173 
174 		public ClientBuilder authorities(String... authorities) {
175 			for (String authority : authorities) {
176 				this.authorities.add(authority);
177 			}
178 			return this;
179 		}
180 
181 		public ClientBuilder autoApprove(boolean autoApprove) {
182 			this.autoApprove = autoApprove;
183 			return this;
184 		}
185 
186 		public ClientBuilder autoApprove(String... scopes) {
187 			for (String scope : scopes) {
188 				this.autoApproveScopes.add(scope);
189 			}
190 			return this;
191 		}
192 
193 		public ClientBuilder additionalInformation(Map<String, ?> map) {
194 			this.additionalInformation.putAll(map);
195 			return this;
196 		}
197 
198 		public ClientBuilder additionalInformation(String... pairs) {
199 			for (String pair : pairs) {
200 				String separator = ":";
201 				if (!pair.contains(separator) && pair.contains("=")) {
202 					separator = "=";
203 				}
204 				int index = pair.indexOf(separator);
205 				String key = pair.substring(0, index > 0 ? index : pair.length());
206 				String value = index > 0 ? pair.substring(index+1) : null;
207 				this.additionalInformation.put(key, (Object) value);
208 			}
209 			return this;
210 		}
211 
212 		public ClientDetailsServiceBuilder<B> and() {
213 			return ClientDetailsServiceBuilder.this;
214 		}
215 
216 		private ClientBuilder(String clientId) {
217 			this.clientId = clientId;
218 		}
219 
220 	}
221 
222 }