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