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 @Override
116 public void onResponseStatus( Buffer version, int status, Buffer reason )
117 throws IOException
118 {
119 if (Log.isDebugEnabled())
120 Log.debug("SecurityListener:Response Status: " + status );
121
122 if ( status == HttpStatus.UNAUTHORIZED_401 && _attempts<_destination.getHttpClient().maxRetries())
123 {
124
125 setDelegatingResponses(false);
126 _needIntercept = true;
127 }
128 else
129 {
130 setDelegatingResponses(true);
131 setDelegatingRequests(true);
132 _needIntercept = false;
133 }
134 super.onResponseStatus(version,status,reason);
135 }
136
137
138 @Override
139 public void onResponseHeader( Buffer name, Buffer value )
140 throws IOException
141 {
142 if (Log.isDebugEnabled())
143 Log.debug( "SecurityListener:Header: " + name.toString() + " / " + value.toString() );
144
145
146 if (!isDelegatingResponses())
147 {
148 int header = HttpHeaders.CACHE.getOrdinal(name);
149 switch (header)
150 {
151 case HttpHeaders.WWW_AUTHENTICATE_ORDINAL:
152
153
154 String authString = value.toString();
155 String type = scrapeAuthenticationType( authString );
156
157
158 Map<String,String> details = scrapeAuthenticationDetails( authString );
159 String pathSpec="/";
160 RealmResolver realmResolver = _destination.getHttpClient().getRealmResolver();
161
162 if ( realmResolver == null )
163 {
164 break;
165 }
166
167 Realm realm = realmResolver.getRealm( details.get("realm"), _destination, pathSpec );
168
169 if ( realm == null )
170 {
171 Log.warn( "Unknown Security Realm: " + details.get("realm") );
172 }
173 else if ("digest".equalsIgnoreCase(type))
174 {
175 _destination.addAuthorization("/",new DigestAuthentication(realm,details));
176
177 }
178 else if ("basic".equalsIgnoreCase(type))
179 {
180 _destination.addAuthorization(pathSpec,new BasicAuthentication(realm));
181 }
182
183 break;
184 }
185 }
186 super.onResponseHeader(name,value);
187 }
188
189
190 @Override
191 public void onRequestComplete() throws IOException
192 {
193 _requestComplete = true;
194
195 if (_needIntercept)
196 {
197 if (_requestComplete && _responseComplete)
198 {
199 if (Log.isDebugEnabled())
200 Log.debug("onRequestComplete, Both complete: Resending from onResponseComplete "+_exchange);
201 _responseComplete = false;
202 _requestComplete = false;
203 setDelegatingRequests(true);
204 setDelegatingResponses(true);
205 _destination.resend(_exchange);
206 }
207 else
208 {
209 if (Log.isDebugEnabled())
210 Log.debug("onRequestComplete, Response not yet complete onRequestComplete, calling super for "+_exchange);
211 super.onRequestComplete();
212 }
213 }
214 else
215 {
216 if (Log.isDebugEnabled())
217 Log.debug("onRequestComplete, delegating to super with Request complete="+_requestComplete+", response complete="+_responseComplete+" "+_exchange);
218 super.onRequestComplete();
219 }
220 }
221
222
223 @Override
224 public void onResponseComplete() throws IOException
225 {
226 _responseComplete = true;
227 if (_needIntercept)
228 {
229 if (_requestComplete && _responseComplete)
230 {
231 if (Log.isDebugEnabled())
232 Log.debug("onResponseComplete, Both complete: Resending from onResponseComplete"+_exchange);
233 _responseComplete = false;
234 _requestComplete = false;
235 setDelegatingResponses(true);
236 setDelegatingRequests(true);
237 _destination.resend(_exchange);
238
239 }
240 else
241 {
242 if (Log.isDebugEnabled())
243 Log.debug("onResponseComplete, Request not yet complete from onResponseComplete, calling super "+_exchange);
244 super.onResponseComplete();
245 }
246 }
247 else
248 {
249 if (Log.isDebugEnabled())
250 Log.debug("OnResponseComplete, delegating to super with Request complete="+_requestComplete+", response complete="+_responseComplete+" "+_exchange);
251 super.onResponseComplete();
252 }
253 }
254
255 @Override
256 public void onRetry()
257 {
258 _attempts++;
259 setDelegatingRequests(true);
260 setDelegatingResponses(true);
261 _requestComplete=false;
262 _responseComplete=false;
263 _needIntercept=false;
264 super.onRetry();
265 }
266
267
268 }