1
2
3
4
5
6
7
8
9
10
11
12
13
14 package org.eclipse.jetty.client.security;
15
16 import java.io.IOException;
17 import java.util.HashMap;
18 import java.util.Map;
19 import java.util.StringTokenizer;
20
21 import org.eclipse.jetty.client.HttpDestination;
22 import org.eclipse.jetty.client.HttpEventListenerWrapper;
23 import org.eclipse.jetty.client.HttpExchange;
24 import org.eclipse.jetty.http.HttpHeaders;
25 import org.eclipse.jetty.http.HttpStatus;
26 import org.eclipse.jetty.io.Buffer;
27 import org.eclipse.jetty.util.StringUtil;
28 import org.eclipse.jetty.util.log.Log;
29
30
31
32
33
34
35
36
37 public class SecurityListener extends HttpEventListenerWrapper
38 {
39 private HttpDestination _destination;
40 private HttpExchange _exchange;
41 private boolean _requestComplete;
42 private boolean _responseComplete;
43 private boolean _needIntercept;
44
45 private int _attempts = 0;
46
47 public SecurityListener(HttpDestination destination, HttpExchange ex)
48 {
49
50
51 super(ex.getEventListener(),true);
52 _destination=destination;
53 _exchange=ex;
54 }
55
56
57
58
59
60
61
62
63 protected String scrapeAuthenticationType( String authString )
64 {
65 String authType;
66
67 if ( authString.indexOf( " " ) == -1 )
68 {
69 authType = authString.toString().trim();
70 }
71 else
72 {
73 String authResponse = authString.toString();
74 authType = authResponse.substring( 0, authResponse.indexOf( " " ) ).trim();
75 }
76 return authType;
77 }
78
79
80
81
82
83
84
85 protected Map<String, String> scrapeAuthenticationDetails( String authString )
86 {
87 Map<String, String> authenticationDetails = new HashMap<String, String>();
88 authString = authString.substring( authString.indexOf( " " ) + 1, authString.length() );
89 StringTokenizer strtok = new StringTokenizer( authString, ",");
90
91 while ( strtok.hasMoreTokens() )
92 {
93 String token = strtok.nextToken();
94 String[] pair = token.split( "=" );
95
96
97 if ( pair.length == 2 )
98 {
99 String itemName = pair[0].trim();
100 String itemValue = pair[1].trim();
101
102 itemValue = StringUtil.unquote( itemValue );
103
104 authenticationDetails.put( itemName, itemValue );
105 }
106 else
107 {
108 Log.debug("SecurityListener: missed scraping authentication details - " + token );
109 }
110 }
111 return authenticationDetails;
112 }
113
114
115 public void onResponseStatus( Buffer version, int status, Buffer reason )
116 throws IOException
117 {
118 if (Log.isDebugEnabled())
119 Log.debug("SecurityListener:Response Status: " + status );
120
121 if ( status == HttpStatus.UNAUTHORIZED_401 && _attempts<_destination.getHttpClient().maxRetries())
122 {
123
124 setDelegatingResponses(false);
125 _needIntercept = true;
126 }
127 else
128 {
129 setDelegatingResponses(true);
130 setDelegatingRequests(true);
131 _needIntercept = false;
132 }
133 super.onResponseStatus(version,status,reason);
134 }
135
136
137 public void onResponseHeader( Buffer name, Buffer value )
138 throws IOException
139 {
140 if (Log.isDebugEnabled())
141 Log.debug( "SecurityListener:Header: " + name.toString() + " / " + value.toString() );
142
143
144 if (!isDelegatingResponses())
145 {
146 int header = HttpHeaders.CACHE.getOrdinal(name);
147 switch (header)
148 {
149 case HttpHeaders.WWW_AUTHENTICATE_ORDINAL:
150
151
152 String authString = value.toString();
153 String type = scrapeAuthenticationType( authString );
154
155
156 Map<String,String> details = scrapeAuthenticationDetails( authString );
157 String pathSpec="/";
158 RealmResolver realmResolver = _destination.getHttpClient().getRealmResolver();
159
160 if ( realmResolver == null )
161 {
162 break;
163 }
164
165 Realm realm = realmResolver.getRealm( details.get("realm"), _destination, pathSpec );
166
167 if ( realm == null )
168 {
169 Log.warn( "Unknown Security Realm: " + details.get("realm") );
170 }
171 else if ("digest".equalsIgnoreCase(type))
172 {
173 _destination.addAuthorization("/",new DigestAuthorization(realm,details));
174
175 }
176 else if ("basic".equalsIgnoreCase(type))
177 {
178 _destination.addAuthorization(pathSpec,new BasicAuthorization(realm));
179 }
180
181 break;
182 }
183 }
184 super.onResponseHeader(name,value);
185 }
186
187
188 public void onRequestComplete() throws IOException
189 {
190 _requestComplete = true;
191
192 if (_needIntercept)
193 {
194 if (_requestComplete && _responseComplete)
195 {
196 if (Log.isDebugEnabled())
197 Log.debug("onRequestComplete, Both complete: Resending from onResponseComplete "+_exchange);
198 _responseComplete = false;
199 _requestComplete = false;
200 setDelegatingRequests(true);
201 setDelegatingResponses(true);
202 _destination.resend(_exchange);
203 }
204 else
205 {
206 if (Log.isDebugEnabled())
207 Log.debug("onRequestComplete, Response not yet complete onRequestComplete, calling super for "+_exchange);
208 super.onRequestComplete();
209 }
210 }
211 else
212 {
213 if (Log.isDebugEnabled())
214 Log.debug("onRequestComplete, delegating to super with Request complete="+_requestComplete+", response complete="+_responseComplete+" "+_exchange);
215 super.onRequestComplete();
216 }
217 }
218
219
220 public void onResponseComplete() throws IOException
221 {
222 _responseComplete = true;
223 if (_needIntercept)
224 {
225 if (_requestComplete && _responseComplete)
226 {
227 if (Log.isDebugEnabled())
228 Log.debug("onResponseComplete, Both complete: Resending from onResponseComplete"+_exchange);
229 _responseComplete = false;
230 _requestComplete = false;
231 setDelegatingResponses(true);
232 setDelegatingRequests(true);
233 _destination.resend(_exchange);
234
235 }
236 else
237 {
238 if (Log.isDebugEnabled())
239 Log.debug("onResponseComplete, Request not yet complete from onResponseComplete, calling super "+_exchange);
240 super.onResponseComplete();
241 }
242 }
243 else
244 {
245 if (Log.isDebugEnabled())
246 Log.debug("OnResponseComplete, delegating to super with Request complete="+_requestComplete+", response complete="+_responseComplete+" "+_exchange);
247 super.onResponseComplete();
248 }
249 }
250
251 public void onRetry()
252 {
253 _attempts++;
254 setDelegatingRequests(true);
255 setDelegatingResponses(true);
256 _requestComplete=false;
257 _responseComplete=false;
258 _needIntercept=false;
259 super.onRetry();
260 }
261
262
263 }