View Javadoc

1   //
2   //  ========================================================================
3   //  Copyright (c) 1995-2013 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  
19  package org.eclipse.jetty.client.security;
20  
21  
22  import java.io.IOException;
23  import java.security.MessageDigest;
24  import java.util.Map;
25  
26  import org.eclipse.jetty.client.HttpExchange;
27  import org.eclipse.jetty.http.HttpHeaders;
28  import org.eclipse.jetty.util.StringUtil;
29  import org.eclipse.jetty.util.TypeUtil;
30  
31  public 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 }