Package org.apache.catalina.authenticator

Source Code of org.apache.catalina.authenticator.TesterDigestAuthenticatorPerformance$TesterRunnable

/*
*  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.
*/
package org.apache.catalina.authenticator;

import java.io.IOException;
import java.security.MessageDigest;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import static org.junit.Assert.assertEquals;

import org.junit.Test;

import org.apache.catalina.Context;
import org.apache.catalina.deploy.LoginConfig;
import org.apache.catalina.deploy.SecurityCollection;
import org.apache.catalina.deploy.SecurityConstraint;
import org.apache.catalina.startup.TestTomcat.MapRealm;
import org.apache.catalina.startup.TesterServlet;
import org.apache.catalina.startup.Tomcat;
import org.apache.catalina.startup.TomcatBaseTest;
import org.apache.catalina.util.MD5Encoder;
import org.apache.tomcat.util.buf.ByteChunk;

public class TesterDigestAuthenticatorPerformance extends TomcatBaseTest {

    private static String USER = "user";
    private static String PWD = "pwd";
    private static String ROLE = "role";
    private static String URI = "/protected";
    private static String CONTEXT_PATH = "/foo";
    private static String CLIENT_AUTH_HEADER = "authorization";
    private static String REALM = "TestRealm";
    private static String QOP = "auth";

    @Test
    public void testSimple() throws Exception {
        doTest(100, 1000);
    }

    public void doTest(int threadCount, int requestCount) throws Exception {
       
        getTomcatInstance().start();

        TesterRunnable runnables[] = new TesterRunnable[threadCount];
        Thread threads[] = new Thread[threadCount];
       
        // Create the runnables & threads
        for (int i = 0; i < threadCount; i++) {
            runnables[i] = new TesterRunnable(i, requestCount);
            threads[i] = new Thread(runnables[i]);
        }

        long start = System.currentTimeMillis();

        // Start the threads
        for (int i = 0; i < threadCount; i++) {
            threads[i].start();
        }
       
        // Wait for the threads to finish
        for (int i = 0; i < threadCount; i++) {
            threads[i].join();
        }
        double wallTime = System.currentTimeMillis() - start;
       
        // Gather the results...
        double totalTime = 0;
        int totalSuccess = 0;
        for (int i = 0; i < threadCount; i++) {
            System.out.println("Thread: " + i + " Success: " +
                    runnables[i].getSuccess());
            totalSuccess = totalSuccess + runnables[i].getSuccess();
            totalTime = totalTime + runnables[i].getTime();
        }
       
        System.out.println("Average time per request (user): " +
                totalTime/(threadCount * requestCount));
        System.out.println("Average time per request (wall): " +
                wallTime/(threadCount * requestCount));
       
        assertEquals(requestCount * threadCount, totalSuccess);
    }

    private class TesterRunnable implements Runnable {

        // Number of valid requests required
        private int requestCount;
       
        private String nonce;
        private String opaque;

        private String cnonce;

        private Map<String,List<String>> reqHeaders;
        private List<String> authHeader;
       
        private MessageDigest digester;
        private MD5Encoder encoder;

        private String md5a1;
        private String md5a2;

        private String path;

        private int success = 0;
        private long time = 0;

        // All init code should be in here. run() needs to be quick
        public TesterRunnable(int id, int requestCount) throws Exception {
            this.requestCount = requestCount;

            path = "http://localhost:" + getPort() + CONTEXT_PATH + URI;

            // Make the first request as we need the Digest challenge to obtain
            // the server nonce
            Map<String,List<String>> respHeaders =
                    new HashMap<String,List<String>>();
            getUrl(path, new ByteChunk(), respHeaders);
           
            nonce = TestDigestAuthenticator.getNonce(respHeaders);
            opaque = TestDigestAuthenticator.getOpaque(respHeaders);
           
            cnonce = "cnonce" + id;

            reqHeaders = new  HashMap<String,List<String>>();
            authHeader = new ArrayList<String>();
            reqHeaders.put(CLIENT_AUTH_HEADER, authHeader);
           
            digester = MessageDigest.getInstance("MD5");
            encoder = new MD5Encoder();

            String a1 = USER + ":" + REALM + ":" + PWD;
            String a2 = "GET:" + CONTEXT_PATH + URI;
           
            md5a1 = encoder.encode(digester.digest(a1.getBytes()));
            md5a2 = encoder.encode(digester.digest(a2.getBytes()));
        }

        @Override
        public void run() {
            int rc;
            int nc = 0;
            ByteChunk bc = new ByteChunk();
            long start = System.currentTimeMillis();
            for (int i = 0; i < requestCount; i++) {
                nc++;
                authHeader.clear();
                authHeader.add(buildDigestResponse(nc));
               
                rc = -1;
                bc.recycle();
                bc.reset();
               
                try {
                    rc = getUrl(path, bc, reqHeaders, null);
                } catch (IOException ioe) {
                    // Ignore
                }
            
                if (rc == 200 && "OK".equals(bc.toString())) {
                    success++;
                }
            }
            time = System.currentTimeMillis() - start;
        }
       
        public int getSuccess() {
            return success;
        }

        public long getTime() {
            return time;
        }

        private String buildDigestResponse(int nc) {
           
            String ncString = String.format("%1$08x", Integer.valueOf(nc));

            String response = md5a1 + ":" + nonce + ":" + ncString + ":" +
                    cnonce + ":" + QOP + ":" + md5a2;

            String md5response =
                encoder.encode(digester.digest(response.getBytes()));
   
            StringBuilder auth = new StringBuilder();
            auth.append("Digest username=\"");
            auth.append(USER);
            auth.append("\", realm=\"");
            auth.append(REALM);
            auth.append("\", nonce=\"");
            auth.append(nonce);
            auth.append("\", uri=\"");
            auth.append(CONTEXT_PATH + URI);
            auth.append("\", opaque=\"");
            auth.append(opaque);
            auth.append("\", response=\"");
            auth.append(md5response);
            auth.append("\"");
            auth.append(", qop=\"");
            auth.append(QOP);
            auth.append("\"");
            auth.append(", nc=\"");
            auth.append(ncString);
            auth.append("\"");
            auth.append(", cnonce=\"");
            auth.append(cnonce);
            auth.append("\"");

            return auth.toString();
        }
    }

    @Override
    public void setUp() throws Exception {
        super.setUp();

        // Configure a context with digest auth and a single protected resource
        Tomcat tomcat = getTomcatInstance();
       
        // Must have a real docBase - just use temp
        Context ctxt = tomcat.addContext(CONTEXT_PATH,
                System.getProperty("java.io.tmpdir"));
       
        // Add protected servlet
        Tomcat.addServlet(ctxt, "TesterServlet", new TesterServlet());
        ctxt.addServletMapping(URI, "TesterServlet");
        SecurityCollection collection = new SecurityCollection();
        collection.addPattern(URI);
        SecurityConstraint sc = new SecurityConstraint();
        sc.addAuthRole(ROLE);
        sc.addCollection(collection);
        ctxt.addConstraint(sc);
       
        // Configure the Realm
        MapRealm realm = new MapRealm();
        realm.addUser(USER, PWD);
        realm.addUserRole(USER, ROLE);
        ctxt.setRealm(realm);
       
        // Configure the authenticator
        LoginConfig lc = new LoginConfig();
        lc.setAuthMethod("DIGEST");
        lc.setRealmName(REALM);
        ctxt.setLoginConfig(lc);
        DigestAuthenticator authenticator = new DigestAuthenticator();
        authenticator.setCnonceCacheSize(100);
        ctxt.getPipeline().addValve(authenticator);
    }
}
TOP

Related Classes of org.apache.catalina.authenticator.TesterDigestAuthenticatorPerformance$TesterRunnable

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.