All Downloads are FREE. Search and download functionalities are using the official Maven repository.

io.milton.http.http11.auth.DigestHelper Maven / Gradle / Ivy

/*
 * 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 io.milton.http.http11.auth;

import io.milton.http.Auth;
import io.milton.http.Request.Method;
import io.milton.http.http11.auth.NonceProvider.NonceValidity;

import java.io.UnsupportedEncodingException;

import org.apache.commons.codec.binary.Base64;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 *
 */
public class DigestHelper {

    private static final Logger log = LoggerFactory.getLogger( DigestHelper.class );

    private final NonceProvider nonceProvider;

    public DigestHelper(NonceProvider nonceProvider) {
        this.nonceProvider = nonceProvider;
    }
                
    public DigestResponse calculateResponse( Auth auth, String expectedRealm, Method method ) {
		try {
			// Check all required parameters were supplied (ie RFC 2069)
			if( ( auth.getUser() == null ) || ( auth.getRealm() == null ) || ( auth.getNonce() == null ) || ( auth.getUri() == null ) ) {
				log.warn( "missing params" );
				return null;
			}

			// Check all required parameters for an "auth" qop were supplied (ie RFC 2617)
			Long nc;
			if( "auth".equals( auth.getQop() ) ) {
				if( ( auth.getNc() == null ) || ( auth.getCnonce() == null ) ) {
					log.warn( "missing params: nc and/or cnonce" );
					return null;
				}
				nc = Long.parseLong( auth.getNc(), 16); // the nonce-count. hex value, must always increase
			} else {
				nc = null;
			}

			// Check realm name equals what we expected
			if( expectedRealm == null ) throw new IllegalStateException( "realm is null");
			if( !expectedRealm.equals( auth.getRealm() ) ) {
				log.warn( "incorrect realm: resource: " + expectedRealm + " given: " + auth.getRealm() );
				return null;
			}

			// Check nonce was a Base64 encoded (as sent by DigestProcessingFilterEntryPoint)
			if( !Base64.isBase64(auth.getNonce().getBytes("UTF-8"))) {
				log.warn( "nonce not base64 encoded" );
				return null;
			}

			log.debug( "nc: " + auth.getNc());


			// Decode nonce from Base64
			// format of nonce is
			//   base64(expirationTime + "" + md5Hex(expirationTime + "" + key))
			String plainTextNonce = new String( Base64.decodeBase64( auth.getNonce().getBytes("UTF-8") ) );
			NonceValidity validity = nonceProvider.getNonceValidity( plainTextNonce, nc, auth.getUser() );
	//        if( NonceValidity.INVALID.equals( validity ) ) {
	//            log.debug( "invalid nonce: " + plainTextNonce );
	//            return null;
	//        } else if( NonceValidity.EXPIRED.equals( validity ) ) {
	//            log.debug( "expired nonce: " + plainTextNonce );
	//            // make this known so that we can add stale field to challenge
	//            auth.setNonceStale( true );
	//            return null;
	//        }

			return toDigestResponse( auth, method );
		} catch (UnsupportedEncodingException ex) {
			throw new RuntimeException(ex);
		}
    }

    public String getChallenge( String nonceValue, Auth auth, String actualRealm ) {
		try {
			String nonceValueBase64 = new String( Base64.encodeBase64( nonceValue.getBytes("UTF-8") ) );

			// qop is quality of protection, as defined by RFC 2617.
			// we do not use opaque due to IE violation of RFC 2617 in not
			// representing opaque on subsequent requests in same session.
			String authenticateHeader = "Digest realm=\"" + actualRealm
				+ "\", " + "qop=\"auth\", nonce=\"" + nonceValueBase64
				+ "\"";

			if( auth != null ) {
				if( auth.isNonceStale() ) {
					authenticateHeader = authenticateHeader
						+ ", stale=\"true\"";
				}
			}

			return authenticateHeader;
		} catch (UnsupportedEncodingException ex) {
			throw new RuntimeException(ex);
		}
    }


    private DigestResponse toDigestResponse( Auth auth, Method m ) {
		return new DigestResponse(
			m,
			auth.getUser(),
			auth.getRealm(),
			auth.getNonce(),
			auth.getUri(),
			auth.getResponseDigest(),
			auth.getQop(),
			auth.getNc(),
			auth.getCnonce() );

    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy