1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.opensaml.saml2.metadata.provider;
18
19 import java.io.IOException;
20 import java.net.URI;
21 import java.net.URISyntaxException;
22
23 import org.apache.commons.httpclient.HttpClient;
24 import org.apache.commons.httpclient.UsernamePasswordCredentials;
25 import org.apache.commons.httpclient.auth.AuthScope;
26 import org.apache.commons.httpclient.methods.GetMethod;
27 import org.apache.commons.httpclient.params.HttpClientParams;
28 import org.apache.commons.httpclient.protocol.Protocol;
29 import org.apache.commons.httpclient.protocol.ProtocolSocketFactory;
30 import org.joda.time.DateTime;
31 import org.opensaml.saml2.common.SAML2Helper;
32 import org.opensaml.xml.XMLObject;
33 import org.opensaml.xml.io.UnmarshallingException;
34 import org.slf4j.Logger;
35 import org.slf4j.LoggerFactory;
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51 public class HTTPMetadataProvider extends AbstractObservableMetadataProvider {
52
53
54 private XMLObject cachedMetadata;
55
56
57 private final Logger log = LoggerFactory.getLogger(HTTPMetadataProvider.class);
58
59
60 private URI metadataURI;
61
62
63 private boolean maintainExpiredMetadata;
64
65
66 private HttpClient httpClient;
67
68
69 private AuthScope authScope;
70
71
72 private int maxCacheDuration;
73
74
75 private DateTime mdExpirationTime;
76
77
78
79
80
81
82
83
84
85
86 public HTTPMetadataProvider(String metadataURL, int requestTimeout) throws MetadataProviderException {
87 super();
88 try {
89 metadataURI = new URI(metadataURL);
90 maintainExpiredMetadata = true;
91
92 HttpClientParams clientParams = new HttpClientParams();
93 clientParams.setSoTimeout(requestTimeout);
94 httpClient = new HttpClient(clientParams);
95 httpClient.getHttpConnectionManager().getParams().setConnectionTimeout(requestTimeout);
96 authScope = new AuthScope(metadataURI.getHost(), metadataURI.getPort());
97
98
99 maxCacheDuration = 60 * 60 * 24;
100 } catch (URISyntaxException e) {
101 throw new MetadataProviderException("Illegal URL syntax", e);
102 }
103 }
104
105
106
107
108
109
110 public void initialize() throws MetadataProviderException {
111 refreshMetadata();
112 }
113
114
115
116
117
118
119 public String getMetadataURI() {
120 return metadataURI.toASCIIString();
121 }
122
123
124
125
126
127
128 public boolean maintainExpiredMetadata() {
129 return maintainExpiredMetadata;
130 }
131
132
133
134
135
136
137 public void setMaintainExpiredMetadata(boolean maintain) {
138 maintainExpiredMetadata = maintain;
139 }
140
141
142
143
144
145
146
147
148 public void setBasicCredentials(String username, String password) {
149 if (username == null && password == null) {
150 httpClient.getState().setCredentials(null, null);
151 } else {
152 UsernamePasswordCredentials credentials = new UsernamePasswordCredentials(username, password);
153 httpClient.getState().setCredentials(authScope, credentials);
154 }
155 }
156
157
158
159
160
161
162 public int getRequestTimeout() {
163 return httpClient.getParams().getSoTimeout();
164 }
165
166
167
168
169
170
171
172
173 public void setSocketFactory(ProtocolSocketFactory newSocketFactory) {
174 log.debug("Using the custom socket factory {} to connect to the HTTP server", newSocketFactory.getClass()
175 .getName());
176 Protocol protocol = new Protocol(metadataURI.getScheme(), newSocketFactory, metadataURI.getPort());
177 httpClient.getHostConfiguration().setHost(metadataURI.getHost(), metadataURI.getPort(), protocol);
178 }
179
180
181
182
183
184
185 public int getMaxCacheDuration() {
186 return maxCacheDuration;
187 }
188
189
190
191
192
193
194 public void setMaxCacheDuration(int newDuration) {
195 maxCacheDuration = newDuration;
196 }
197
198
199 public XMLObject getMetadata() throws MetadataProviderException {
200 if (mdExpirationTime.isBeforeNow()) {
201 log.debug("Cached metadata is stale, refreshing");
202 refreshMetadata();
203 }
204
205 return cachedMetadata;
206 }
207
208
209
210
211
212
213 protected void cacheMetadata(XMLObject metadata) {
214 cachedMetadata = metadata;
215 }
216
217
218
219
220
221
222
223 protected synchronized void refreshMetadata() throws MetadataProviderException {
224 if (mdExpirationTime != null && !mdExpirationTime.isBeforeNow()) {
225
226 return;
227 }
228
229 log.debug("Refreshing cache of metadata from URL {}, max cache duration set to {} seconds", metadataURI,
230 maxCacheDuration);
231 try {
232 XMLObject metadata = fetchMetadata();
233
234 log.debug("Calculating expiration time");
235 DateTime now = new DateTime();
236 mdExpirationTime = SAML2Helper.getEarliestExpiration(metadata, now.plus(maxCacheDuration * 1000), now);
237 log.debug("Metadata cache expires on " + mdExpirationTime);
238
239 if (mdExpirationTime != null && !maintainExpiredMetadata() && mdExpirationTime.isBeforeNow()) {
240 cachedMetadata = null;
241 } else {
242 filterMetadata(metadata);
243 releaseMetadataDOM(metadata);
244 cachedMetadata = metadata;
245 }
246
247 emitChangeEvent();
248 } catch (IOException e) {
249 String errorMsg = "Unable to read metadata from server";
250 log.error(errorMsg, e);
251 throw new MetadataProviderException(errorMsg, e);
252 } catch (UnmarshallingException e) {
253 String errorMsg = "Unable to unmarshall metadata";
254 log.error(errorMsg, e);
255 throw new MetadataProviderException(errorMsg, e);
256 } catch (FilterException e) {
257 String errorMsg = "Unable to filter metadata";
258 log.error(errorMsg, e);
259 throw new MetadataProviderException(errorMsg, e);
260 }
261 }
262
263
264
265
266
267
268
269
270
271 protected XMLObject fetchMetadata() throws IOException, UnmarshallingException {
272 log.debug("Fetching metadata document from remote server");
273 GetMethod getMethod = new GetMethod(getMetadataURI());
274 if (httpClient.getState().getCredentials(authScope) != null) {
275 log.debug("Using BASIC authentication when retrieving metadata");
276 getMethod.setDoAuthentication(true);
277 }
278 httpClient.executeMethod(getMethod);
279
280 if (log.isTraceEnabled()) {
281 log.trace("Retrieved the following metadata document\n{}", getMethod.getResponseBodyAsString());
282 }
283 XMLObject metadata = unmarshallMetadata(getMethod.getResponseBodyAsStream());
284
285 log.debug("Unmarshalled metadata from remote server");
286 return metadata;
287
288 }
289 }