/* * ==================================================================== * * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Apache Software Foundation. For more * information on the Apache Software Foundation, please see * <http://www.apache.org/>. * */ package org.apache.ogt.http.impl.auth; import java.util.HashMap; import java.util.Map; import org.apache.ogt.http.Header; import org.apache.ogt.http.HeaderElement; import org.apache.ogt.http.HttpRequest; import org.apache.ogt.http.auth.AUTH; import org.apache.ogt.http.auth.AuthScheme; import org.apache.ogt.http.auth.Credentials; import org.apache.ogt.http.auth.MalformedChallengeException; import org.apache.ogt.http.auth.UsernamePasswordCredentials; import org.apache.ogt.http.impl.auth.DigestScheme; import org.apache.ogt.http.message.BasicHeader; import org.apache.ogt.http.message.BasicHeaderValueParser; import org.apache.ogt.http.message.BasicHttpRequest; import org.junit.Assert; import org.junit.Test; /** * Test Methods for DigestScheme Authentication. */ public class TestDigestScheme { @Test(expected=MalformedChallengeException.class) public void testDigestAuthenticationWithNoRealm() throws Exception { Header authChallenge = new BasicHeader(AUTH.WWW_AUTH, "Digest"); AuthScheme authscheme = new DigestScheme(); authscheme.processChallenge(authChallenge); } @Test(expected=MalformedChallengeException.class) public void testDigestAuthenticationWithNoRealm2() throws Exception { Header authChallenge = new BasicHeader(AUTH.WWW_AUTH, "Digest "); AuthScheme authscheme = new DigestScheme(); authscheme.processChallenge(authChallenge); } @Test public void testDigestAuthenticationWithDefaultCreds() throws Exception { String challenge = "Digest realm=\"realm1\", nonce=\"f2a3f18799759d4f1a1c068b92b573cb\""; Header authChallenge = new BasicHeader(AUTH.WWW_AUTH, challenge); HttpRequest request = new BasicHttpRequest("Simple", "/"); Credentials cred = new UsernamePasswordCredentials("username","password"); DigestScheme authscheme = new DigestScheme(); authscheme.processChallenge(authChallenge); Header authResponse = authscheme.authenticate(cred, request); Map<String, String> table = parseAuthResponse(authResponse); Assert.assertEquals("username", table.get("username")); Assert.assertEquals("realm1", table.get("realm")); Assert.assertEquals("/", table.get("uri")); Assert.assertEquals("f2a3f18799759d4f1a1c068b92b573cb", table.get("nonce")); Assert.assertEquals("e95a7ddf37c2eab009568b1ed134f89a", table.get("response")); } @Test public void testDigestAuthentication() throws Exception { String challenge = "Digest realm=\"realm1\", nonce=\"f2a3f18799759d4f1a1c068b92b573cb\""; Header authChallenge = new BasicHeader(AUTH.WWW_AUTH, challenge); HttpRequest request = new BasicHttpRequest("Simple", "/"); Credentials cred = new UsernamePasswordCredentials("username","password"); DigestScheme authscheme = new DigestScheme(); authscheme.processChallenge(authChallenge); Header authResponse = authscheme.authenticate(cred, request); Map<String, String> table = parseAuthResponse(authResponse); Assert.assertEquals("username", table.get("username")); Assert.assertEquals("realm1", table.get("realm")); Assert.assertEquals("/", table.get("uri")); Assert.assertEquals("f2a3f18799759d4f1a1c068b92b573cb", table.get("nonce")); Assert.assertEquals("e95a7ddf37c2eab009568b1ed134f89a", table.get("response")); } @Test public void testDigestAuthenticationWithSHA() throws Exception { String challenge = "Digest realm=\"realm1\", " + "nonce=\"f2a3f18799759d4f1a1c068b92b573cb\", " + "algorithm=SHA"; Header authChallenge = new BasicHeader(AUTH.WWW_AUTH, challenge); HttpRequest request = new BasicHttpRequest("Simple", "/"); Credentials cred = new UsernamePasswordCredentials("username","password"); DigestScheme authscheme = new DigestScheme(); authscheme.processChallenge(authChallenge); Header authResponse = authscheme.authenticate(cred, request); Map<String, String> table = parseAuthResponse(authResponse); Assert.assertEquals("username", table.get("username")); Assert.assertEquals("realm1", table.get("realm")); Assert.assertEquals("/", table.get("uri")); Assert.assertEquals("f2a3f18799759d4f1a1c068b92b573cb", table.get("nonce")); Assert.assertEquals("8769e82e4e28ecc040b969562b9050580c6d186d", table.get("response")); } @Test public void testDigestAuthenticationWithQueryStringInDigestURI() throws Exception { String challenge = "Digest realm=\"realm1\", nonce=\"f2a3f18799759d4f1a1c068b92b573cb\""; Header authChallenge = new BasicHeader(AUTH.WWW_AUTH, challenge); HttpRequest request = new BasicHttpRequest("Simple", "/?param=value"); Credentials cred = new UsernamePasswordCredentials("username","password"); DigestScheme authscheme = new DigestScheme(); authscheme.processChallenge(authChallenge); Header authResponse = authscheme.authenticate(cred, request); Map<String, String> table = parseAuthResponse(authResponse); Assert.assertEquals("username", table.get("username")); Assert.assertEquals("realm1", table.get("realm")); Assert.assertEquals("/?param=value", table.get("uri")); Assert.assertEquals("f2a3f18799759d4f1a1c068b92b573cb", table.get("nonce")); Assert.assertEquals("a847f58f5fef0bc087bcb9c3eb30e042", table.get("response")); } @Test public void testDigestAuthenticationWithMultipleRealms() throws Exception { String challenge1 = "Digest realm=\"realm1\", nonce=\"abcde\""; String challenge2 = "Digest realm=\"realm2\", nonce=\"123546\""; Credentials cred = new UsernamePasswordCredentials("username","password"); Credentials cred2 = new UsernamePasswordCredentials("uname2","password2"); Header authChallenge = new BasicHeader(AUTH.WWW_AUTH, challenge1); HttpRequest request = new BasicHttpRequest("Simple", "/"); DigestScheme authscheme = new DigestScheme(); authscheme.processChallenge(authChallenge); Header authResponse = authscheme.authenticate(cred, request); Map<String, String> table = parseAuthResponse(authResponse); Assert.assertEquals("username", table.get("username")); Assert.assertEquals("realm1", table.get("realm")); Assert.assertEquals("/", table.get("uri")); Assert.assertEquals("abcde", table.get("nonce")); Assert.assertEquals("786f500303eac1478f3c2865e676ed68", table.get("response")); authChallenge = new BasicHeader(AUTH.WWW_AUTH, challenge2); DigestScheme authscheme2 = new DigestScheme(); authscheme2.processChallenge(authChallenge); authResponse = authscheme2.authenticate(cred2, request); table = parseAuthResponse(authResponse); Assert.assertEquals("uname2", table.get("username")); Assert.assertEquals("realm2", table.get("realm")); Assert.assertEquals("/", table.get("uri")); Assert.assertEquals("123546", table.get("nonce")); Assert.assertEquals("0283edd9ef06a38b378b3b74661391e9", table.get("response")); } /** * Test digest authentication using the MD5-sess algorithm. */ @Test public void testDigestAuthenticationMD5Sess() throws Exception { // Example using Digest auth with MD5-sess String realm="realm"; String username="username"; String password="password"; String nonce="e273f1776275974f1a120d8b92c5b3cb"; String challenge="Digest realm=\"" + realm + "\", " + "nonce=\"" + nonce + "\", " + "opaque=\"SomeString\", " + "stale=false, " + "algorithm=MD5-sess, " + "qop=\"auth,auth-int\""; // we pass both but expect auth to be used Header authChallenge = new BasicHeader(AUTH.WWW_AUTH, challenge); Credentials cred = new UsernamePasswordCredentials(username, password); HttpRequest request = new BasicHttpRequest("Simple", "/"); DigestScheme authscheme = new DigestScheme(); authscheme.processChallenge(authChallenge); Header authResponse = authscheme.authenticate(cred, request); String response = authResponse.getValue(); Assert.assertTrue(response.indexOf("nc=00000001") > 0); // test for quotes Assert.assertTrue(response.indexOf("qop=auth") > 0); // test for quotes Map<String, String> table = parseAuthResponse(authResponse); Assert.assertEquals(username, table.get("username")); Assert.assertEquals(realm, table.get("realm")); Assert.assertEquals("MD5-sess", table.get("algorithm")); Assert.assertEquals("/", table.get("uri")); Assert.assertEquals(nonce, table.get("nonce")); Assert.assertEquals(1, Integer.parseInt(table.get("nc"),16)); Assert.assertTrue(null != table.get("cnonce")); Assert.assertEquals("SomeString", table.get("opaque")); Assert.assertEquals("auth", table.get("qop")); //@TODO: add better check Assert.assertTrue(null != table.get("response")); } /** * Test digest authentication using the MD5-sess algorithm. */ @Test public void testDigestAuthenticationMD5SessNoQop() throws Exception { // Example using Digest auth with MD5-sess String realm="realm"; String username="username"; String password="password"; String nonce="e273f1776275974f1a120d8b92c5b3cb"; String challenge="Digest realm=\"" + realm + "\", " + "nonce=\"" + nonce + "\", " + "opaque=\"SomeString\", " + "stale=false, " + "algorithm=MD5-sess"; Header authChallenge = new BasicHeader(AUTH.WWW_AUTH, challenge); Credentials cred = new UsernamePasswordCredentials(username, password); HttpRequest request = new BasicHttpRequest("Simple", "/"); DigestScheme authscheme = new DigestScheme(); authscheme.processChallenge(authChallenge); Header authResponse = authscheme.authenticate(cred, request); Map<String, String> table = parseAuthResponse(authResponse); Assert.assertEquals(username, table.get("username")); Assert.assertEquals(realm, table.get("realm")); Assert.assertEquals("MD5-sess", table.get("algorithm")); Assert.assertEquals("/", table.get("uri")); Assert.assertEquals(nonce, table.get("nonce")); Assert.assertTrue(null == table.get("nc")); Assert.assertEquals("SomeString", table.get("opaque")); Assert.assertTrue(null == table.get("qop")); //@TODO: add better check Assert.assertTrue(null != table.get("response")); } /** * Test digest authentication with invalud qop value */ @Test(expected=MalformedChallengeException.class) public void testDigestAuthenticationMD5SessInvalidQop() throws Exception { // Example using Digest auth with MD5-sess String realm="realm"; String nonce="e273f1776275974f1a120d8b92c5b3cb"; String challenge="Digest realm=\"" + realm + "\", " + "nonce=\"" + nonce + "\", " + "opaque=\"SomeString\", " + "stale=false, " + "algorithm=MD5-sess, " + "qop=\"jakarta\""; // jakarta is an invalid qop value Header authChallenge = new BasicHeader(AUTH.WWW_AUTH, challenge); AuthScheme authscheme = new DigestScheme(); authscheme.processChallenge(authChallenge); } @Test public void testDigestAuthenticationWithStaleNonce() throws Exception { String challenge = "Digest realm=\"realm1\", " + "nonce=\"f2a3f18799759d4f1a1c068b92b573cb\", stale=\"true\""; Header authChallenge = new BasicHeader(AUTH.WWW_AUTH, challenge); AuthScheme authscheme = new DigestScheme(); authscheme.processChallenge(authChallenge); Assert.assertFalse(authscheme.isComplete()); } private static Map<String, String> parseAuthResponse(final Header authResponse) { String s = authResponse.getValue(); if (!s.startsWith("Digest ")) { return null; } HeaderElement[] elements = BasicHeaderValueParser.parseElements(s.substring(7), null); Map<String, String> map = new HashMap<String, String>(elements.length); for (int i = 0; i < elements.length; i++) { HeaderElement element = elements[i]; map.put(element.getName(), element.getValue()); } return map; } @Test public void testDigestNouceCount() throws Exception { String challenge1 = "Digest realm=\"realm1\", nonce=\"f2a3f18799759d4f1a1c068b92b573cb\", qop=auth"; Header authChallenge1 = new BasicHeader(AUTH.WWW_AUTH, challenge1); HttpRequest request = new BasicHttpRequest("Simple", "/"); Credentials cred = new UsernamePasswordCredentials("username","password"); DigestScheme authscheme = new DigestScheme(); authscheme.processChallenge(authChallenge1); Header authResponse1 = authscheme.authenticate(cred, request); Map<String, String> table1 = parseAuthResponse(authResponse1); Assert.assertEquals("00000001", table1.get("nc")); Header authResponse2 = authscheme.authenticate(cred, request); Map<String, String> table2 = parseAuthResponse(authResponse2); Assert.assertEquals("00000002", table2.get("nc")); String challenge2 = "Digest realm=\"realm1\", nonce=\"f2a3f18799759d4f1a1c068b92b573cb\", qop=auth"; Header authChallenge2 = new BasicHeader(AUTH.WWW_AUTH, challenge2); authscheme.processChallenge(authChallenge2); Header authResponse3 = authscheme.authenticate(cred, request); Map<String, String> table3 = parseAuthResponse(authResponse3); Assert.assertEquals("00000003", table3.get("nc")); String challenge3 = "Digest realm=\"realm1\", nonce=\"e273f1776275974f1a120d8b92c5b3cb\", qop=auth"; Header authChallenge3 = new BasicHeader(AUTH.WWW_AUTH, challenge3); authscheme.processChallenge(authChallenge3); Header authResponse4 = authscheme.authenticate(cred, request); Map<String, String> table4 = parseAuthResponse(authResponse4); Assert.assertEquals("00000001", table4.get("nc")); } }