Package org.restlet.ext.crypto.internal

Source Code of org.restlet.ext.crypto.internal.DigestVerifier

/**
* Copyright 2005-2011 Noelios Technologies.
*
* The contents of this file are subject to the terms of one of the following
* open source licenses: LGPL 3.0 or LGPL 2.1 or CDDL 1.0 or EPL 1.0 (the
* "Licenses"). You can select the license that you prefer but you may not use
* this file except in compliance with one of these Licenses.
*
* You can obtain a copy of the LGPL 3.0 license at
* http://www.opensource.org/licenses/lgpl-3.0.html
*
* You can obtain a copy of the LGPL 2.1 license at
* http://www.opensource.org/licenses/lgpl-2.1.php
*
* You can obtain a copy of the CDDL 1.0 license at
* http://www.opensource.org/licenses/cddl1.php
*
* You can obtain a copy of the EPL 1.0 license at
* http://www.opensource.org/licenses/eclipse-1.0.php
*
* See the Licenses for the specific language governing permissions and
* limitations under the Licenses.
*
* Alternatively, you can obtain a royalty free commercial license with less
* limitations, transferable or non-transferable, directly at
* http://www.noelios.com/products/restlet-engine
*
* Restlet is a registered trademark of Noelios Technologies.
*/

package org.restlet.ext.crypto.internal;

import org.restlet.Request;
import org.restlet.Response;
import org.restlet.data.ChallengeResponse;
import org.restlet.data.Digest;
import org.restlet.data.Reference;
import org.restlet.engine.security.AuthenticatorUtils;
import org.restlet.ext.crypto.DigestAuthenticator;
import org.restlet.ext.crypto.DigestUtils;
import org.restlet.security.LocalVerifier;
import org.restlet.security.User;

/**
* Verifier for the HTTP DIGEST authentication scheme. Note that the "A1" hash
* specified in RFC 2617 is available via the
* {@link #getWrappedSecretDigest(String)} method.
*
* @author Jerome Louvel
*/
public class DigestVerifier extends
        org.restlet.ext.crypto.DigestVerifier<LocalVerifier> {

    /** The associated digest authenticator. */
    private DigestAuthenticator digestAuthenticator;

    /**
     * Constructor.
     *
     * @param digestAuthenticator
     *            The associated digest authenticator.
     * @param wrappedAlgorithm
     *            The digest algorithm of secrets provided by the wrapped
     *            verifier.
     * @param wrappedVerifier
     *            The wrapped secret verifier.
     */
    public DigestVerifier(DigestAuthenticator digestAuthenticator,
            LocalVerifier wrappedVerifier, String wrappedAlgorithm) {
        super(Digest.ALGORITHM_HTTP_DIGEST, wrappedVerifier, wrappedAlgorithm);
        this.digestAuthenticator = digestAuthenticator;
    }

    /**
     * If the algorithm is {@link Digest#ALGORITHM_HTTP_DIGEST}, then is
     * retrieves the realm for {@link #getDigestAuthenticator()} to compute the
     * digest, otherwise, it keeps the default behavior.
     */
    @Override
    protected char[] digest(String identifier, char[] secret, String algorithm) {
        if (Digest.ALGORITHM_HTTP_DIGEST.equals(algorithm)) {
            String result = DigestUtils.toHttpDigest(identifier, secret,
                    getDigestAuthenticator().getRealm());
            if (result != null) {
                return result.toCharArray();
            }

            return null;
        }

        return super.digest(identifier, secret, algorithm);
    }

    /**
     * Returns the associated digest authenticator.
     *
     * @return The associated digest authenticator.
     */
    public DigestAuthenticator getDigestAuthenticator() {
        return digestAuthenticator;
    }

    /**
     * Sets the associated digest authenticator.
     *
     * @param digestAuthenticator
     *            The associated digest authenticator.
     */
    public void setDigestAuthenticator(DigestAuthenticator digestAuthenticator) {
        this.digestAuthenticator = digestAuthenticator;
    }

    @Override
    public int verify(Request request, Response response) {
        int result = RESULT_VALID;
        ChallengeResponse cr = request.getChallengeResponse();

        if (cr == null) {
            result = RESULT_MISSING;
        } else {
            String nonce = cr.getServerNonce();
            String uri = (cr.getDigestRef() == null) ? null : cr.getDigestRef()
                    .toString();
            String qop = cr.getQuality();
            int nc = cr.getServerNounceCount();
            String cnonce = cr.getClientNonce();
            String username = getIdentifier(request, response);
            String cresponse = null;
            char[] secret = getSecret(request, response);
            if (secret != null) {
                cresponse = new String(secret);
            } else {
                result = RESULT_INVALID;
            }

            try {
                if (!DigestHelper.isNonceValid(nonce, getDigestAuthenticator()
                        .getServerKey(), getDigestAuthenticator()
                        .getMaxServerNonceAge())) {
                    // Nonce expired, send challenge request with stale=true
                    result = RESULT_STALE;
                }
            } catch (Exception ce) {
                // Invalid nonce, probably doesn't match serverKey
                result = RESULT_INVALID;
            }

            if (result == RESULT_VALID) {
                if (AuthenticatorUtils.anyNull(nonce, uri)) {
                    result = RESULT_MISSING;
                } else {
                    Reference resourceRef = request.getResourceRef();
                    String requestUri = resourceRef.getPath();

                    if ((resourceRef.getQuery() != null)
                            && (uri.indexOf('?') > -1)) {
                        // IE neglects to include the query string, so
                        // the workaround is to leave it off
                        // unless both the calculated URI and the
                        // specified URI contain a query string
                        requestUri += "?" + resourceRef.getQuery();
                    }

                    if (uri.equals(requestUri)) {
                        char[] a1 = getWrappedSecretDigest(username);
                        if (a1 != null) {
                            String a2 = DigestUtils.toMd5(request.getMethod()
                                    .toString() + ":" + requestUri);
                            StringBuilder expectedResponse = new StringBuilder()
                                    .append(a1).append(':').append(nonce);
                            if (!AuthenticatorUtils.anyNull(qop, cnonce, nc)) {
                                expectedResponse
                                        .append(':')
                                        .append(AuthenticatorUtils
                                                .formatNonceCount(nc))
                                        .append(':').append(cnonce).append(':')
                                        .append(qop);
                            }
                            expectedResponse.append(':').append(a2);

                            if (!DigestUtils.toMd5(expectedResponse.toString())
                                    .equals(cresponse)) {
                                result = RESULT_INVALID;
                            }
                        } else {
                            // The HA1 is null
                            result = RESULT_INVALID;
                        }
                    } else {
                        // The request URI doesn't match
                        result = RESULT_INVALID;
                    }
                }
            }

            if (result == RESULT_VALID) {
                request.getClientInfo().setUser(new User(username));
            }
        }

        return result;
    }

}
TOP

Related Classes of org.restlet.ext.crypto.internal.DigestVerifier

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.