1// 2// ======================================================================== 3// Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd. 4// ------------------------------------------------------------------------ 5// All rights reserved. This program and the accompanying materials 6// are made available under the terms of the Eclipse Public License v1.0 7// and Apache License v2.0 which accompanies this distribution. 8// 9// The Eclipse Public License is available at 10// http://www.eclipse.org/legal/epl-v10.html 11// 12// The Apache License v2.0 is available at 13// http://www.opensource.org/licenses/apache2.0.php 14// 15// You may elect to redistribute this code under either of these licenses. 16// ======================================================================== 17// 18 19package org.eclipse.jetty.client.security; 20 21 22import java.io.IOException; 23import java.security.MessageDigest; 24import java.util.Map; 25 26import org.eclipse.jetty.client.HttpExchange; 27import org.eclipse.jetty.http.HttpHeaders; 28import org.eclipse.jetty.util.StringUtil; 29import org.eclipse.jetty.util.TypeUtil; 30 31public class DigestAuthentication implements Authentication 32{ 33 private static final String NC = "00000001"; 34 Realm securityRealm; 35 Map details; 36 37 public DigestAuthentication(Realm realm, Map details) 38 { 39 this.securityRealm=realm; 40 this.details=details; 41 } 42 43 44 public void setCredentials( HttpExchange exchange ) 45 throws IOException 46 { 47 StringBuilder buffer = new StringBuilder().append("Digest"); 48 49 buffer.append(" ").append("username").append('=').append('"').append(securityRealm.getPrincipal()).append('"'); 50 51 buffer.append(", ").append("realm").append('=').append('"').append(String.valueOf(details.get("realm"))).append('"'); 52 53 buffer.append(", ").append("nonce").append('=').append('"').append(String.valueOf(details.get("nonce"))).append('"'); 54 55 buffer.append(", ").append("uri").append('=').append('"').append(exchange.getURI()).append('"'); 56 57 buffer.append(", ").append("algorithm").append('=').append(String.valueOf(details.get("algorithm"))); 58 59 String cnonce = newCnonce(exchange, securityRealm, details); 60 61 buffer.append(", ").append("response").append('=').append('"').append(newResponse(cnonce, 62 exchange, securityRealm, details)).append('"'); 63 64 buffer.append(", ").append("qop").append('=').append(String.valueOf(details.get("qop"))); 65 66 67 buffer.append(", ").append("nc").append('=').append(NC); 68 69 buffer.append(", ").append("cnonce").append('=').append('"').append(cnonce).append('"'); 70 71 exchange.setRequestHeader( HttpHeaders.AUTHORIZATION, 72 new String(buffer.toString().getBytes(StringUtil.__ISO_8859_1))); 73 } 74 75 protected String newResponse(String cnonce, HttpExchange exchange, Realm securityRealm, Map details) 76 { 77 try{ 78 MessageDigest md = MessageDigest.getInstance("MD5"); 79 80 // calc A1 digest 81 md.update(securityRealm.getPrincipal().getBytes(StringUtil.__ISO_8859_1)); 82 md.update((byte)':'); 83 md.update(String.valueOf(details.get("realm")).getBytes(StringUtil.__ISO_8859_1)); 84 md.update((byte)':'); 85 md.update(securityRealm.getCredentials().getBytes(StringUtil.__ISO_8859_1)); 86 byte[] ha1 = md.digest(); 87 // calc A2 digest 88 md.reset(); 89 md.update(exchange.getMethod().getBytes(StringUtil.__ISO_8859_1)); 90 md.update((byte)':'); 91 md.update(exchange.getURI().getBytes(StringUtil.__ISO_8859_1)); 92 byte[] ha2=md.digest(); 93 94 md.update(TypeUtil.toString(ha1,16).getBytes(StringUtil.__ISO_8859_1)); 95 md.update((byte)':'); 96 md.update(String.valueOf(details.get("nonce")).getBytes(StringUtil.__ISO_8859_1)); 97 md.update((byte)':'); 98 md.update(NC.getBytes(StringUtil.__ISO_8859_1)); 99 md.update((byte)':'); 100 md.update(cnonce.getBytes(StringUtil.__ISO_8859_1)); 101 md.update((byte)':'); 102 md.update(String.valueOf(details.get("qop")).getBytes(StringUtil.__ISO_8859_1)); 103 md.update((byte)':'); 104 md.update(TypeUtil.toString(ha2,16).getBytes(StringUtil.__ISO_8859_1)); 105 byte[] digest=md.digest(); 106 107 // check digest 108 return encode(digest); 109 } 110 catch(Exception e) 111 { 112 throw new RuntimeException(e); 113 } 114 } 115 116 protected String newCnonce(HttpExchange exchange, Realm securityRealm, Map details) 117 { 118 try 119 { 120 MessageDigest md = MessageDigest.getInstance("MD5"); 121 byte[] b= md.digest(String.valueOf(System.currentTimeMillis()).getBytes(StringUtil.__ISO_8859_1)); 122 return encode(b); 123 } 124 catch(Exception e) 125 { 126 throw new RuntimeException(e); 127 } 128 } 129 130 private static String encode(byte[] data) 131 { 132 StringBuilder buffer = new StringBuilder(); 133 for (int i=0; i<data.length; i++) 134 { 135 buffer.append(Integer.toHexString((data[i] & 0xf0) >>> 4)); 136 buffer.append(Integer.toHexString(data[i] & 0x0f)); 137 } 138 return buffer.toString(); 139 } 140 141} 142