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