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