Java tutorial
/* * Copyright (C) 2012 McEvoy Software Ltd * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. * */ package com.bradmcevoy.http.http11.auth; import com.bradmcevoy.http.Auth; import com.bradmcevoy.http.Request.Method; import com.bradmcevoy.http.http11.auth.NonceProvider.NonceValidity; 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) { // 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.isArrayByteBase64(auth.getNonce().getBytes())) { 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())); NonceValidity validity = nonceProvider.getNonceValidity(plainTextNonce, nc); // 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; // } DigestResponse resp = toDigestResponse(auth, method); return resp; } public String getChallenge(String nonceValue, Auth auth, String actualRealm) { String nonceValueBase64 = new String(Base64.encodeBase64(nonceValue.getBytes())); // 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; } private DigestResponse toDigestResponse(Auth auth, Method m) { DigestResponse dr = new DigestResponse(m, auth.getUser(), auth.getRealm(), auth.getNonce(), auth.getUri(), auth.getResponseDigest(), auth.getQop(), auth.getNc(), auth.getCnonce()); return dr; } }