/**
* The contents of this file are subject to the terms
* of the Common Development and Distribution License
* (the License). You may not use this file except in
* compliance with the License.
*
* You can obtain a copy of the license at
* https://glassfish.dev.java.net/public/CDDLv1.0.html or
* glassfish/bootstrap/legal/CDDLv1.0.txt.
* See the License for the specific language governing
* permissions and limitations under the License.
*
* When distributing Covered Code, include this CDDL
* Header Notice in each file and include the License file
* at glassfish/bootstrap/legal/CDDLv1.0.txt.
* If applicable, add the following below the CDDL Header,
* with the fields enclosed by brackets [] replaced by
* you own identifying information:
* "Portions Copyrighted [year] [name of copyright owner]"
*
* Copyright (c) Ericsson AB, 2004-2007. All rights reserved.
* Copyright 1997-2009 Sun Microsystems, Inc. All rights reserved.
*/
package org.jvnet.glassfish.comms.security.auth.impl;
import static com.sun.enterprise.security.auth.digest.api.Constants.*;
import com.sun.enterprise.security.auth.digest.api.DigestAlgorithmParameter;
import com.sun.enterprise.security.auth.digest.api.NestedDigestAlgoParam;
import com.sun.enterprise.security.auth.digest.api.Password;
import com.sun.enterprise.security.auth.digest.impl.DigestAlgorithmParameterImpl;
import com.sun.enterprise.security.auth.digest.impl.DigestProcessor;
import com.sun.enterprise.security.auth.digest.impl.KeyDigestAlgoParamImpl;
import com.sun.enterprise.security.auth.digest.impl.NestedDigestAlgoParamImpl;
import static org.jvnet.glassfish.comms.security.util.Constants.securityLogger;
import java.security.NoSuchAlgorithmException;
import java.security.spec.AlgorithmParameterSpec;
import java.util.List;
import java.util.Properties;
import java.util.logging.Level;
import javax.servlet.ServletInputStream;
import javax.servlet.sip.AuthInfo;
import javax.servlet.sip.SipServletRequest;
import javax.servlet.sip.SipServletResponse;
/**
*
* @author K.Venugopal@sun.com
*/
public class ClientDigestCreator {
public void createDigest(AuthInfo ai, SipServletRequest request,
SipServletResponse response) {
AuthHeaderProcessor ahp = new AuthHeaderProcessor();
List<String> headers = null;
headers = ahp.getHeaderValues(response, "Proxy-Authenticate");
process(headers, ai, request, response, response.SC_PROXY_AUTHENTICATION_REQUIRED);
headers = ahp.getHeaderValues(response, "WWW-Authenticate");
process(headers, ai, request, response, response.SC_UNAUTHORIZED);
String value = response.getHeader("Authentication-Info");
// if (value != null && value.length() > 0) {
// int index = value.indexOf(":");
// if (index == -1) {
// return;
// }
// value = value.substring(index);
// AuthInfoImpl aii = (AuthInfoImpl)ai;
// Properties props = new HeaderParser().parse(value);
// Iterator<String> realms =aii.getRealmNames();
// while(realms.hasNext()){
// String realm = realms.next();
// int statuscode = aii.getStatusCode(realm);
// process(props,realm,ai,request,response,statuscode);
// }
// }
}
private void process(List<String> headers, AuthInfo ai, SipServletRequest request, SipServletResponse response, int headerType) {
for (String value : headers) {
//support for single header. TODO : Change to check realm and muliple headers
try {
String qop = null;
String method = response.getMethod();
String cnonce = null;
String nonce = null;
String algorithm = null;
String uri = null;
String realm = null;
String username = null;
String entityBody = null;
String nc = "00000001";
String opaque = null;
ServletInputStream sis = null;
Properties props = new HeaderParser().parse(value);
realm = props.getProperty("realm");
nonce = props.getProperty("nonce");
qop = props.getProperty("qop");
if (qop !=null && qop.contains("auth")) {
qop = "auth";
}else if (qop !=null && qop.contains("auth-int")) {
qop = "auth-int";
}
algorithm = props.getProperty("algorithm");
if (algorithm == null || algorithm.length() == 0) {
algorithm = "MD5";
}
opaque = props.getProperty("opaque");
username = ((AuthInfoImpl) ai).getUserName(realm);
final String password = ((AuthInfoImpl) ai).getPassword(realm);
uri = request.getRequestURI().toString();
method = request.getMethod();
long time = System.currentTimeMillis();
cnonce = Authenticator.createNonce(request.getLocalAddr(),
String.valueOf(time));
DigestAlgorithmParameter key = new KeyDigestAlgoParamImpl(algorithm,
username, realm);
DigestAlgorithmParameter a2 = getA2(method, uri, algorithm,
qop, entityBody);
DigestAlgorithmParameter p1 = new DigestAlgorithmParameterImpl(NONCE,
nonce.getBytes());
com.sun.enterprise.security.auth.digest.api.DigestAlgorithmParameter[] list =
null;
if ("auth-int".equals(qop) || "auth".equals(qop)) {
DigestAlgorithmParameterImpl p2 = new DigestAlgorithmParameterImpl(NONCE_COUNT,
nc.getBytes());
DigestAlgorithmParameterImpl p3 = new DigestAlgorithmParameterImpl(CNONCE,
cnonce.getBytes());
DigestAlgorithmParameterImpl p4 = new DigestAlgorithmParameterImpl(QOP,
qop.getBytes());
list = new DigestAlgorithmParameter[5];
list[0] = p1;
list[1] = p2;
list[2] = p3;
list[3] = p4;
list[4] = a2;
} else {
list = new DigestAlgorithmParameter[2];
list[0] = p1;
list[1] = a2;
}
NestedDigestAlgoParam data = new NestedDigestAlgoParamImpl(DATA, list);
DigestAlgorithmParameter[] dataList = new DigestAlgorithmParameter[2];
dataList[0] = key;
dataList[1] = data;
Password pwd = new Password() {
public int getType() {
return Password.PLAIN_TEXT;
}
public byte[] getValue() {
return password.getBytes();
}
};
DigestProcessor dp = new DigestCreator();
String digestValue = dp.createDigest(pwd, dataList);
StringBuffer sb = new StringBuffer();
sb.append("Digest ");
sb.append("realm=\"");
sb.append(realm);
sb.append("\",username=\"");
sb.append(username);
sb.append("\",uri=\"");
sb.append(uri);
sb.append("\",nonce=\"");
sb.append(nonce);
if (qop != null) {
sb.append("\",nc=");
sb.append(nc);
sb.append(",cnonce=\"");
sb.append(cnonce);
sb.append("\",qop=\"");
sb.append(qop);
}
sb.append("\",response=\"");
sb.append(digestValue);
sb.append("\"");
sb.append(",algorithm=");
sb.append(algorithm);
if (opaque != null) {
sb.append(",opaque=\"");
sb.append(opaque);
sb.append("\"");
}
if (headerType == response.SC_PROXY_AUTHENTICATION_REQUIRED) {
request.addHeader("Proxy-Authorization", sb.toString());
} else if (headerType == response.SC_UNAUTHORIZED) {
request.addHeader("Authorization", sb.toString());
}
} catch (NoSuchAlgorithmException ex) {
securityLogger.log(Level.SEVERE, null, ex);
}
}
}
private void process(Properties props, String realm, AuthInfo ai, SipServletRequest request, SipServletResponse response, int headerType) {
try {
String qop = null;
String method = response.getMethod();
String cnonce = null;
String nonce = null;
String algorithm = null;
String uri = null;
String username = null;
String entityBody = null;
String nc = "00000001";
String opaque = null;
ServletInputStream sis = null;
nonce = props.getProperty("nextnonce");
qop = props.getProperty("qop");
if (qop !=null && qop.contains("auth-int")) {
qop = "auth-int";
} else if (qop !=null && qop.contains("auth")) {
qop = "auth";
}
algorithm = props.getProperty("algorithm");
if (algorithm == null || algorithm.length() == 0) {
algorithm = "MD5";
}
opaque = props.getProperty("opaque");
username = ((AuthInfoImpl) ai).getUserName(realm);
final String password = ((AuthInfoImpl) ai).getPassword(realm);
uri = request.getRequestURI().toString();
method = request.getMethod();
long time = System.currentTimeMillis();
cnonce = Authenticator.createNonce(request.getLocalAddr(),
String.valueOf(time));
DigestAlgorithmParameter key = new KeyDigestAlgoParamImpl(algorithm,
username, realm);
DigestAlgorithmParameter a2 = getA2(method, uri, algorithm,
qop, entityBody);
DigestAlgorithmParameter p1 = new DigestAlgorithmParameterImpl(NONCE,
nonce.getBytes());
com.sun.enterprise.security.auth.digest.api.DigestAlgorithmParameter[] list =
null;
if ("auth-int".equals(qop) || "auth".equals(qop)) {
DigestAlgorithmParameterImpl p2 = new DigestAlgorithmParameterImpl(NONCE_COUNT,
nc.getBytes());
DigestAlgorithmParameterImpl p3 = new DigestAlgorithmParameterImpl(CNONCE,
cnonce.getBytes());
DigestAlgorithmParameterImpl p4 = new DigestAlgorithmParameterImpl(QOP,
qop.getBytes());
list = new DigestAlgorithmParameter[5];
list[0] = p1;
list[1] = p2;
list[2] = p3;
list[3] = p4;
list[4] = a2;
} else {
list = new DigestAlgorithmParameter[2];
list[0] = p1;
list[1] = a2;
}
NestedDigestAlgoParam data = new NestedDigestAlgoParamImpl(DATA, list);
DigestAlgorithmParameter[] dataList = new DigestAlgorithmParameter[2];
dataList[0] = key;
dataList[1] = data;
Password pwd = new Password() {
public int getType() {
return Password.PLAIN_TEXT;
}
public byte[] getValue() {
return password.getBytes();
}
};
DigestProcessor dp = new DigestCreator();
String digestValue = dp.createDigest(pwd, dataList);
StringBuffer sb = new StringBuffer();
sb.append("Digest ");
sb.append("realm=\"");
sb.append(realm);
sb.append("\",username=\"");
sb.append(username);
sb.append("\",uri=\"");
sb.append(uri);
sb.append("\",nonce=\"");
sb.append(nonce);
if (qop != null) {
sb.append("\",nc=");
sb.append(nc);
sb.append(",cnonce=\"");
sb.append(cnonce);
sb.append("\",qop=\"");
sb.append(qop);
}
sb.append("\",response=\"");
sb.append(digestValue);
sb.append("\"");
sb.append(",algorithm=");
sb.append(algorithm);
if (opaque != null) {
sb.append(",opaque=\"");
sb.append(opaque);
sb.append("\"");
}
if (headerType == response.SC_PROXY_AUTHENTICATION_REQUIRED) {
request.addHeader("Proxy-Authorization", sb.toString());
} else if (headerType == response.SC_UNAUTHORIZED) {
request.addHeader("Authorization", sb.toString());
}
} catch (NoSuchAlgorithmException ex) {
securityLogger.log(Level.SEVERE, null, ex);
}
}
protected DigestAlgorithmParameter getA2(String method, String uri,
String algorithm, String qop, String entityBody) {
DigestAlgorithmParameterImpl p1 = new DigestAlgorithmParameterImpl(METHOD,
method.getBytes());
DigestAlgorithmParameterImpl p2 = new DigestAlgorithmParameterImpl(URI,
uri.getBytes());
if ("auth".equals(qop) || qop == null) {
DigestAlgorithmParameterImpl[] list = new DigestAlgorithmParameterImpl[2];
list[0] = p1;
list[1] = p2;
NestedDigestAlgoParamImpl a2 = new NestedDigestAlgoParamImpl(algorithm,
A2, list);
return a2;
} else if ("auth-int".equals(qop)) {
AlgorithmParameterSpec[] list = new AlgorithmParameterSpec[3];
DigestAlgorithmParameterImpl p3 = new DigestAlgorithmParameterImpl("enity-body",
algorithm, entityBody.getBytes());
list[0] = p1;
list[1] = p2;
list[2] = p3;
NestedDigestAlgoParamImpl a2 = new NestedDigestAlgoParamImpl(algorithm,
A2, list);
return a2;
}
return null;
}
class DigestCreator extends DigestProcessor {
protected boolean validate(Password arg0,
DigestAlgorithmParameter[] arg1) throws NoSuchAlgorithmException {
throw new UnsupportedOperationException("Not supported yet.");
}
}
}