This project has retired. For details please refer to its Attic page.
StandardAuthenticationProvider xref
View Javadoc

1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one
3    * or more contributor license agreements.  See the NOTICE file
4    * distributed with this work for additional information
5    * regarding copyright ownership.  The ASF licenses this file
6    * to you under the Apache License, Version 2.0 (the
7    * "License"); you may not use this file except in compliance
8    * with the License.  You may obtain a copy of the License at
9    *
10   * http://www.apache.org/licenses/LICENSE-2.0
11   *
12   * Unless required by applicable law or agreed to in writing,
13   * software distributed under the License is distributed on an
14   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15   * KIND, either express or implied.  See the License for the
16   * specific language governing permissions and limitations
17   * under the License.
18   */
19  package org.apache.chemistry.opencmis.client.bindings.spi;
20  
21  import java.io.UnsupportedEncodingException;
22  import java.util.ArrayList;
23  import java.util.Collections;
24  import java.util.HashMap;
25  import java.util.List;
26  import java.util.Map;
27  import java.util.concurrent.locks.ReentrantReadWriteLock;
28  
29  import org.apache.chemistry.opencmis.client.bindings.spi.cookies.CmisCookieManager;
30  import org.apache.chemistry.opencmis.commons.SessionParameter;
31  import org.apache.chemistry.opencmis.commons.exceptions.CmisRuntimeException;
32  import org.apache.chemistry.opencmis.commons.impl.Base64;
33  import org.apache.chemistry.opencmis.commons.impl.DateTimeHelper;
34  import org.apache.chemistry.opencmis.commons.impl.IOUtils;
35  import org.apache.chemistry.opencmis.commons.impl.XMLUtils;
36  import org.w3c.dom.Document;
37  import org.w3c.dom.Element;
38  
39  /**
40   * Standard authentication provider class.
41   * 
42   * Adds a basic authentication HTTP header and a WS-Security UsernameToken SOAP
43   * header.
44   */
45  public class StandardAuthenticationProvider extends AbstractAuthenticationProvider {
46  
47      private static final long serialVersionUID = 1L;
48  
49      protected static final String WSSE_NAMESPACE = "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd";
50      protected static final String WSU_NAMESPACE = "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd";
51  
52      private final ReentrantReadWriteLock lock = new ReentrantReadWriteLock();
53  
54      private CmisCookieManager cookieManager;
55      private Map<String, List<String>> fixedHeaders = new HashMap<String, List<String>>();
56      private String csrfHeader;
57      private String csrfValue = "fetch";
58  
59      @Override
60      public void setSession(BindingSession session) {
61          super.setSession(session);
62  
63          if (getHandleCookies() && cookieManager == null) {
64              cookieManager = new CmisCookieManager(session.getSessionId());
65          }
66  
67          boolean sendBasicAuth = getSendBasicAuth();
68  
69          // basic authentication
70          if (sendBasicAuth) {
71              // get user and password
72              String user = getUser();
73              String password = getPassword();
74  
75              // if no user is set, don't set basic auth header
76              if (user != null) {
77                  fixedHeaders.put("Authorization", createBasicAuthHeaderValue(user, password));
78              }
79          }
80  
81          boolean sendBearerToken = getSendBearerToken();
82  
83          // send bearer token
84          if (sendBearerToken) {
85              String token = getBearerToken();
86  
87              // if no token is set, don't set bearer header
88              if (token != null) {
89                  fixedHeaders.put("Authorization", Collections.singletonList("Bearer " + token));
90              }
91          }
92  
93          // proxy authentication
94          if (getProxyUser() != null) {
95              // get proxy user and password
96              String proxyUser = getProxyUser();
97              String proxyPassword = getProxyPassword();
98  
99              fixedHeaders.put("Proxy-Authorization", createBasicAuthHeaderValue(proxyUser, proxyPassword));
100         }
101 
102         // CSRF header
103         csrfHeader = getCsrfHeader();
104 
105         // other headers
106         addSessionParameterHeadersToFixedHeaders();
107     }
108 
109     @Override
110     public Map<String, List<String>> getHTTPHeaders(String url) {
111         Map<String, List<String>> result = new HashMap<String, List<String>>(fixedHeaders);
112 
113         lock.readLock().lock();
114         try {
115             // cookies
116             if (cookieManager != null) {
117                 Map<String, List<String>> cookies = cookieManager.get(url, result);
118                 if (!cookies.isEmpty()) {
119                     result.putAll(cookies);
120                 }
121             }
122 
123             // CSRF header
124             if (csrfHeader != null && csrfValue != null) {
125                 result.put(csrfHeader, Collections.singletonList(csrfValue));
126             }
127         } finally {
128             lock.readLock().unlock();
129         }
130 
131         return result.isEmpty() ? null : result;
132     }
133 
134     @Override
135     public void putResponseHeaders(String url, int statusCode, Map<String, List<String>> headers) {
136         lock.writeLock().lock();
137         try {
138             // cookies
139             if (cookieManager != null) {
140                 cookieManager.put(url, headers);
141             }
142 
143             // CSRF header
144             if (csrfHeader != null) {
145                 for (Map.Entry<String, List<String>> header : headers.entrySet()) {
146                     if (csrfHeader.equalsIgnoreCase(header.getKey())) {
147                         List<String> values = header.getValue();
148                         if (values != null && values.size() > 0) {
149                             csrfValue = values.get(0);
150                         }
151                         break;
152                     }
153                 }
154             }
155         } finally {
156             lock.writeLock().unlock();
157         }
158     }
159 
160     @Override
161     public Element getSOAPHeaders(Object portObject) {
162         // only send SOAP header if configured
163         if (!getSendUsernameToken()) {
164             return null;
165         }
166 
167         // get user and password
168         String user = getUser();
169         String password = getPassword();
170 
171         // if no user is set, don't create SOAP header
172         if (user == null) {
173             return null;
174         }
175 
176         if (password == null) {
177             password = "";
178         }
179 
180         // set time
181         long created = System.currentTimeMillis();
182         long expires = created + 24 * 60 * 60 * 1000; // 24 hours
183 
184         // create the SOAP header
185         try {
186             Document document = XMLUtils.newDomDocument();
187 
188             Element wsseSecurityElement = document.createElementNS(WSSE_NAMESPACE, "Security");
189 
190             Element wsuTimestampElement = document.createElementNS(WSU_NAMESPACE, "Timestamp");
191             wsseSecurityElement.appendChild(wsuTimestampElement);
192 
193             Element tsCreatedElement = document.createElementNS(WSU_NAMESPACE, "Created");
194             tsCreatedElement.appendChild(document.createTextNode(DateTimeHelper.formatXmlDateTime(created)));
195             wsuTimestampElement.appendChild(tsCreatedElement);
196 
197             Element tsExpiresElement = document.createElementNS(WSU_NAMESPACE, "Expires");
198             tsExpiresElement.appendChild(document.createTextNode(DateTimeHelper.formatXmlDateTime(expires)));
199             wsuTimestampElement.appendChild(tsExpiresElement);
200 
201             Element usernameTokenElement = document.createElementNS(WSSE_NAMESPACE, "UsernameToken");
202             wsseSecurityElement.appendChild(usernameTokenElement);
203 
204             Element usernameElement = document.createElementNS(WSSE_NAMESPACE, "Username");
205             usernameElement.appendChild(document.createTextNode(user));
206             usernameTokenElement.appendChild(usernameElement);
207 
208             Element passwordElement = document.createElementNS(WSSE_NAMESPACE, "Password");
209             passwordElement.appendChild(document.createTextNode(password));
210             passwordElement.setAttribute("Type",
211                     "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordText");
212             usernameTokenElement.appendChild(passwordElement);
213 
214             Element createdElement = document.createElementNS(WSU_NAMESPACE, "Created");
215             createdElement.appendChild(document.createTextNode(DateTimeHelper.formatXmlDateTime(created)));
216             usernameTokenElement.appendChild(createdElement);
217 
218             return wsseSecurityElement;
219         } catch (Exception e) {
220             // shouldn't happen...
221             throw new CmisRuntimeException("Could not build SOAP header: " + e.getMessage(), e);
222         }
223     }
224 
225     /**
226      * Returns the HTTP headers that are sent with all requests. The returned
227      * map is mutable but not synchronized!
228      */
229     protected Map<String, List<String>> getFixedHeaders() {
230         return fixedHeaders;
231     }
232 
233     /**
234      * Adds the {@link SessionParameter#HEADER} to the fixed headers. This
235      * method should only be called from the {@link #setSession(BindingSession)}
236      * method to avoid threading issues.
237      */
238     protected void addSessionParameterHeadersToFixedHeaders() {
239         int x = 0;
240         Object headerParam;
241         while ((headerParam = getSession().get(SessionParameter.HEADER + "." + x)) != null) {
242             String header = headerParam.toString();
243             int colon = header.indexOf(':');
244             if (colon > -1) {
245                 String key = header.substring(0, colon).trim();
246                 if (key.length() > 0) {
247                     String value = header.substring(colon + 1).trim();
248                     List<String> values = fixedHeaders.get(key);
249                     if (values == null) {
250                         fixedHeaders.put(key, Collections.singletonList(value));
251                     } else {
252                         List<String> newValues = new ArrayList<String>(values);
253                         newValues.add(value);
254                         fixedHeaders.put(key, newValues);
255                     }
256                 }
257             }
258             x++;
259         }
260     }
261 
262     /**
263      * Creates a basic authentication header value from a username and a
264      * password.
265      */
266     protected List<String> createBasicAuthHeaderValue(String username, String password) {
267         if (password == null) {
268             password = "";
269         }
270 
271         Object charset = getSession().get(SessionParameter.AUTH_HTTP_BASIC_CHARSET);
272         if (charset instanceof String) {
273             charset = ((String) charset).trim();
274         } else {
275             charset = IOUtils.UTF8;
276         }
277 
278         byte[] usernamePassword;
279         try {
280             usernamePassword = (username + ":" + password).getBytes((String) charset);
281         } catch (UnsupportedEncodingException e) {
282             throw new CmisRuntimeException("Unsupported encoding '" + charset + "'!", e);
283         }
284 
285         return Collections.singletonList("Basic " + Base64.encodeBytes(usernamePassword));
286     }
287 
288     /**
289      * Returns if a HTTP Basic Authentication header should be sent. (All
290      * bindings.)
291      */
292     protected boolean getSendBasicAuth() {
293         return getSession().get(SessionParameter.AUTH_HTTP_BASIC, false);
294     }
295 
296     /**
297      * Returns if an OAuth Bearer token header should be sent. (All bindings.)
298      */
299     protected boolean getSendBearerToken() {
300         return getSession().get(SessionParameter.AUTH_OAUTH_BEARER, false);
301     }
302 
303     /**
304      * Returns if a UsernameToken should be sent. (Web Services binding only.)
305      */
306     protected boolean getSendUsernameToken() {
307         return getSession().get(SessionParameter.AUTH_SOAP_USERNAMETOKEN, false);
308     }
309 
310     /**
311      * Returns if the authentication provider should handle cookies.
312      */
313     protected boolean getHandleCookies() {
314         Object value = getSession().get(SessionParameter.COOKIES);
315 
316         if (value instanceof Boolean) {
317             return ((Boolean) value).booleanValue();
318         } else if (value instanceof String) {
319             return Boolean.parseBoolean((String) value);
320         } else if (value == null) {
321             return getCsrfHeader() != null;
322         }
323 
324         return false;
325     }
326 }