chemistry-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From f...@apache.org
Subject svn commit: r1665265 - in /chemistry/opencmis/trunk: chemistry-opencmis-client/chemistry-opencmis-client-bindings/src/main/java/org/apache/chemistry/opencmis/client/bindings/spi/ chemistry-opencmis-commons/chemistry-opencmis-commons-impl/src/main/java/...
Date Mon, 09 Mar 2015 15:49:08 GMT
Author: fmui
Date: Mon Mar  9 15:49:07 2015
New Revision: 1665265

URL: http://svn.apache.org/r1665265
Log:
client: more OAuth improvements 

Modified:
    chemistry/opencmis/trunk/chemistry-opencmis-client/chemistry-opencmis-client-bindings/src/main/java/org/apache/chemistry/opencmis/client/bindings/spi/OAuthAuthenticationProvider.java
    chemistry/opencmis/trunk/chemistry-opencmis-commons/chemistry-opencmis-commons-impl/src/main/java/org/apache/chemistry/opencmis/commons/impl/MimeHelper.java
    chemistry/opencmis/trunk/chemistry-opencmis-commons/chemistry-opencmis-commons-impl/src/test/java/org/apache/chemistry/opencmis/commons/impl/misc/MimeHelperTest.java

Modified: chemistry/opencmis/trunk/chemistry-opencmis-client/chemistry-opencmis-client-bindings/src/main/java/org/apache/chemistry/opencmis/client/bindings/spi/OAuthAuthenticationProvider.java
URL: http://svn.apache.org/viewvc/chemistry/opencmis/trunk/chemistry-opencmis-client/chemistry-opencmis-client-bindings/src/main/java/org/apache/chemistry/opencmis/client/bindings/spi/OAuthAuthenticationProvider.java?rev=1665265&r1=1665264&r2=1665265&view=diff
==============================================================================
--- chemistry/opencmis/trunk/chemistry-opencmis-client/chemistry-opencmis-client-bindings/src/main/java/org/apache/chemistry/opencmis/client/bindings/spi/OAuthAuthenticationProvider.java
(original)
+++ chemistry/opencmis/trunk/chemistry-opencmis-client/chemistry-opencmis-client-bindings/src/main/java/org/apache/chemistry/opencmis/client/bindings/spi/OAuthAuthenticationProvider.java
Mon Mar  9 15:49:07 2015
@@ -38,6 +38,7 @@ import org.apache.chemistry.opencmis.cli
 import org.apache.chemistry.opencmis.commons.SessionParameter;
 import org.apache.chemistry.opencmis.commons.exceptions.CmisConnectionException;
 import org.apache.chemistry.opencmis.commons.impl.IOUtils;
+import org.apache.chemistry.opencmis.commons.impl.MimeHelper;
 import org.apache.chemistry.opencmis.commons.impl.json.JSONObject;
 import org.apache.chemistry.opencmis.commons.impl.json.parser.JSONParser;
 import org.slf4j.Logger;
@@ -132,7 +133,8 @@ import org.slf4j.LoggerFactory;
  *      if (connEx.getCause() instanceof CmisOAuthException) {
  *          CmisOAuthException oauthEx = (CmisOAuthException) connEx.getCause();
  * 
- *          if (CmisOAuthException.ERROR_INVALID_GRANT.equals(oauthEx.getError())) {
+ *          if (CmisOAuthException.ERROR_INVALID_GRANT.equals(oauthEx.getError()) ||
+ *              CmisOAuthException.ERROR_INVALID_TOKEN.equals(oauthEx.getError())) {
  *              // ask the user to authenticate again
  *          } else {
  *             // a configuration or server problem
@@ -474,6 +476,28 @@ public class OAuthAuthenticationProvider
             InputStream stream = null;
 
             int respCode = conn.getResponseCode();
+            if (respCode == 401) {
+                Map<String, Map<String, String>> challenges = MimeHelper.getChallengesFromAuthenticateHeader(conn
+                        .getHeaderField("WWW-Authenticate"));
+
+                if (challenges != null && challenges.containsKey("bearer")) {
+                    Map<String, String> params = challenges.get("bearer");
+
+                    String errorStr = params.get("error");
+                    String descriptionStr = params.get("error_description");
+                    String uriStr = params.get("error_uri");
+
+                    if (LOG.isDebugEnabled()) {
+                        LOG.debug("Invalid OAuth token: {}", params.toString());
+                    }
+
+                    throw new CmisOAuthException("Unauthorized" + (errorStr == null ? ""
: ": " + errorStr)
+                            + (descriptionStr == null ? "" : ": " + descriptionStr), errorStr,
descriptionStr, uriStr);
+                }
+
+                throw new CmisOAuthException("Unauthorized!");
+            }
+
             if (respCode >= 200 && respCode < 300) {
                 stream = conn.getInputStream();
             } else {
@@ -600,6 +624,7 @@ public class OAuthAuthenticationProvider
 
         private static final long serialVersionUID = 1L;
 
+        // general OAuth errors
         public static final String ERROR_INVALID_REQUEST = "invalid_request";
         public static final String ERROR_INVALID_CLIENT = "invalid_client";
         public static final String ERROR_INVALID_GRANT = "invalid_grant";
@@ -607,6 +632,9 @@ public class OAuthAuthenticationProvider
         public static final String ERROR_UNSUPPORTED_GRANT_TYPE = "unsupported_grant_type";
         public static final String ERROR_INVALID_SCOPE = "invalid_scope";
 
+        // bearer specific
+        public static final String ERROR_INVALID_TOKEN = "invalid_token";
+
         private String error;
         private String errorDescription;
         private String errorUri;

Modified: chemistry/opencmis/trunk/chemistry-opencmis-commons/chemistry-opencmis-commons-impl/src/main/java/org/apache/chemistry/opencmis/commons/impl/MimeHelper.java
URL: http://svn.apache.org/viewvc/chemistry/opencmis/trunk/chemistry-opencmis-commons/chemistry-opencmis-commons-impl/src/main/java/org/apache/chemistry/opencmis/commons/impl/MimeHelper.java?rev=1665265&r1=1665264&r2=1665265&view=diff
==============================================================================
--- chemistry/opencmis/trunk/chemistry-opencmis-commons/chemistry-opencmis-commons-impl/src/main/java/org/apache/chemistry/opencmis/commons/impl/MimeHelper.java
(original)
+++ chemistry/opencmis/trunk/chemistry-opencmis-commons/chemistry-opencmis-commons-impl/src/main/java/org/apache/chemistry/opencmis/commons/impl/MimeHelper.java
Mon Mar  9 15:49:07 2015
@@ -239,6 +239,117 @@ public final class MimeHelper {
     }
 
     /**
+     * Parses a WWW-Authenticate header value.
+     * 
+     * @param value
+     *            the header value to parse
+     * 
+     * @return a map with the (lower case) challenge name as key and as the
+     *         value a sub-map with parameters of the challenge
+     */
+    public static Map<String, Map<String, String>> getChallengesFromAuthenticateHeader(String
value) {
+        if (value == null || value.length() == 0) {
+            return null;
+        }
+
+        final String trimValue = value.trim();
+
+        Map<String, Map<String, String>> result = new HashMap<String, Map<String,
String>>();
+
+        boolean inQuotes = false;
+        boolean inName = true;
+        String challenge = null;
+        String paramName = "";
+        StringBuilder sb = new StringBuilder();
+        for (int i = 0; i < trimValue.length(); i++) {
+            char c = trimValue.charAt(i);
+
+            if (c == '\\') {
+                if (!inQuotes) {
+                    return null;
+                }
+                if (trimValue.length() > i && trimValue.charAt(i + 1) == '\\')
{
+                    sb.append('\\');
+                    i++;
+                } else if (trimValue.length() > i && trimValue.charAt(i + 1) ==
'"') {
+                    sb.append('"');
+                    i++;
+                } else {
+                    return null;
+                }
+            } else if (c == '"') {
+                if (inName) {
+                    return null;
+                }
+                if (inQuotes) {
+                    Map<String, String> authMap = result.get(challenge);
+                    if (authMap == null) {
+                        return null;
+                    }
+                    authMap.put(paramName, sb.toString());
+                }
+                sb = new StringBuilder();
+                inQuotes = !inQuotes;
+            } else if (c == '=') {
+                if (inName) {
+                    paramName = sb.toString().trim();
+
+                    int spcIdx = paramName.indexOf(' ');
+                    if (spcIdx > -1) {
+                        challenge = paramName.substring(0, spcIdx).toLowerCase(Locale.ENGLISH);
+                        result.put(challenge, new HashMap<String, String>());
+                        paramName = paramName.substring(spcIdx).trim();
+                    }
+
+                    sb = new StringBuilder();
+                    inName = false;
+                } else if (!inQuotes) {
+                    return null;
+                }
+            } else if (c == ',') {
+                if (inName) {
+                    challenge = sb.toString().trim().toLowerCase(Locale.ENGLISH);
+                    result.put(challenge, new HashMap<String, String>());
+                    sb = new StringBuilder();
+                } else {
+                    if (inQuotes) {
+                        sb.append(c);
+                    } else {
+                        Map<String, String> authMap = result.get(challenge);
+                        if (authMap == null) {
+                            return null;
+                        }
+                        if (!authMap.containsKey(paramName)) {
+                            authMap.put(paramName, sb.toString().trim());
+                        }
+                        sb = new StringBuilder();
+                        inName = true;
+                    }
+                }
+            } else {
+                sb.append(c);
+            }
+        }
+        if (inQuotes) {
+            return null;
+        }
+        if (inName) {
+            challenge = sb.toString().trim().toLowerCase(Locale.ENGLISH);
+            result.put(challenge, new HashMap<String, String>());
+        } else {
+            Map<String, String> authMap = result.get(challenge);
+            if (authMap == null) {
+                return null;
+            }
+            if (!authMap.containsKey(paramName)) {
+                authMap.put(paramName, sb.toString().trim());
+            }
+        }
+
+        return result;
+    }
+
+    /**
      * Gets the boundary from a <code>multipart/formdata</code> content type
      * header.
      * 

Modified: chemistry/opencmis/trunk/chemistry-opencmis-commons/chemistry-opencmis-commons-impl/src/test/java/org/apache/chemistry/opencmis/commons/impl/misc/MimeHelperTest.java
URL: http://svn.apache.org/viewvc/chemistry/opencmis/trunk/chemistry-opencmis-commons/chemistry-opencmis-commons-impl/src/test/java/org/apache/chemistry/opencmis/commons/impl/misc/MimeHelperTest.java?rev=1665265&r1=1665264&r2=1665265&view=diff
==============================================================================
--- chemistry/opencmis/trunk/chemistry-opencmis-commons/chemistry-opencmis-commons-impl/src/test/java/org/apache/chemistry/opencmis/commons/impl/misc/MimeHelperTest.java
(original)
+++ chemistry/opencmis/trunk/chemistry-opencmis-commons/chemistry-opencmis-commons-impl/src/test/java/org/apache/chemistry/opencmis/commons/impl/misc/MimeHelperTest.java
Mon Mar  9 15:49:07 2015
@@ -25,6 +25,7 @@ import static org.apache.chemistry.openc
 import static org.apache.chemistry.opencmis.commons.impl.MimeHelper.decodeContentDispositionFilename;
 import static org.apache.chemistry.opencmis.commons.impl.MimeHelper.encodeContentDisposition;
 import static org.apache.chemistry.opencmis.commons.impl.MimeHelper.getBoundaryFromMultiPart;
+import static org.apache.chemistry.opencmis.commons.impl.MimeHelper.getChallengesFromAuthenticateHeader;
 import static org.apache.chemistry.opencmis.commons.impl.MimeHelper.getCharsetFromContentType;
 import static org.junit.Assert.assertArrayEquals;
 
@@ -105,4 +106,78 @@ public class MimeHelperTest extends Test
         assertArrayEquals(boundary, getBoundaryFromMultiPart("multipart/form-data;boundary="
                 + new String(boundary, IOUtils.ISO_8859_1)));
     }
+
+    @Test
+    public void testAuthenticateHeaderParameters() {
+        Map<String, Map<String, String>> challenges = null;
+
+        challenges = getChallengesFromAuthenticateHeader(null);
+        assertNull(challenges);
+
+        challenges = getChallengesFromAuthenticateHeader("");
+        assertNull(challenges);
+
+        challenges = getChallengesFromAuthenticateHeader("Basic");
+        assertNotNull(challenges);
+        assertTrue(challenges.containsKey("basic"));
+        assertTrue(challenges.get("basic").isEmpty());
+
+        challenges = getChallengesFromAuthenticateHeader("Basic realm=\"example\"");
+        assertNotNull(challenges);
+        assertTrue(challenges.containsKey("basic"));
+        assertEquals("example", challenges.get("basic").get("realm"));
+
+        challenges = getChallengesFromAuthenticateHeader("Basic realm= \"example\" ");
+        assertNotNull(challenges);
+        assertTrue(challenges.containsKey("basic"));
+        assertEquals("example", challenges.get("basic").get("realm"));
+
+        challenges = getChallengesFromAuthenticateHeader("Basic realm=example");
+        assertNotNull(challenges);
+        assertTrue(challenges.containsKey("basic"));
+        assertEquals("example", challenges.get("basic").get("realm"));
+
+        challenges = getChallengesFromAuthenticateHeader("Basic realm=\"example\",charset=\"UTF-8\"");
+        assertNotNull(challenges);
+        assertTrue(challenges.containsKey("basic"));
+        assertEquals("example", challenges.get("basic").get("realm"));
+        assertEquals("UTF-8", challenges.get("basic").get("charset"));
+
+        challenges = getChallengesFromAuthenticateHeader("Bearer realm=\"example\", error=\"invalid_token\"");
+        assertNotNull(challenges);
+        assertTrue(challenges.containsKey("bearer"));
+        assertEquals("example", challenges.get("bearer").get("realm"));
+        assertEquals("invalid_token", challenges.get("bearer").get("error"));
+
+        challenges = getChallengesFromAuthenticateHeader("Bearer realm=\"example\", error=invalid_token");
+        assertNotNull(challenges);
+        assertEquals("example", challenges.get("bearer").get("realm"));
+        assertEquals("invalid_token", challenges.get("bearer").get("error"));
+
+        challenges = getChallengesFromAuthenticateHeader("Bearer realm=\"example\", error=\"invalid_token\",
error_description=\"The access token expired\"");
+        assertNotNull(challenges);
+        assertEquals("example", challenges.get("bearer").get("realm"));
+        assertEquals("invalid_token", challenges.get("bearer").get("error"));
+        assertEquals("The access token expired", challenges.get("bearer").get("error_description"));
+
+        challenges = getChallengesFromAuthenticateHeader("Bearer realm=\"example\",error_description=\"It's
expires, really!\", error=\"invalid_token\",");
+        assertNotNull(challenges);
+        assertEquals("example", challenges.get("bearer").get("realm"));
+        assertEquals("invalid_token", challenges.get("bearer").get("error"));
+        assertEquals("It's expires, really!", challenges.get("bearer").get("error_description"));
+
+        challenges = getChallengesFromAuthenticateHeader("Newauth realm=\"apps\", type=1,
title=\"Login to \\\"apps\\\"\", Basic realm=\"simple\"");
+        assertNotNull(challenges);
+        assertEquals("apps", challenges.get("newauth").get("realm"));
+        assertEquals("1", challenges.get("newauth").get("type"));
+        assertEquals("Login to \"apps\"", challenges.get("newauth").get("title"));
+        assertEquals("simple", challenges.get("basic").get("realm"));
+
+        challenges = getChallengesFromAuthenticateHeader("a1, a2 ,a3 ,a4");
+        assertNotNull(challenges);
+        assertTrue(challenges.containsKey("a1"));
+        assertTrue(challenges.containsKey("a2"));
+        assertTrue(challenges.containsKey("a3"));
+        assertTrue(challenges.containsKey("a4"));
+    }
 }



Mime
View raw message