View Javadoc

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