1 package com.terradue.jcatalogue.client.internal.ahc;
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 import static com.ning.http.util.AsyncHttpProviderUtils.parseCookie;
20 import static com.terradue.jcatalogue.client.internal.lang.Assertions.checkState;
21 import static java.net.HttpURLConnection.HTTP_MOVED_PERM;
22 import static java.net.HttpURLConnection.HTTP_MOVED_TEMP;
23 import static java.net.HttpURLConnection.HTTP_OK;
24 import static java.util.regex.Pattern.CASE_INSENSITIVE;
25
26 import java.net.URI;
27 import java.util.BitSet;
28 import java.util.LinkedList;
29 import java.util.List;
30 import java.util.Map;
31 import java.util.concurrent.ConcurrentHashMap;
32 import java.util.concurrent.ConcurrentMap;
33 import java.util.regex.Pattern;
34
35 import org.slf4j.Logger;
36 import org.slf4j.LoggerFactory;
37
38 import com.ning.http.client.Cookie;
39 import com.ning.http.client.HttpResponseStatus;
40 import com.ning.http.client.RequestBuilder;
41 import com.ning.http.client.filter.FilterContext;
42 import com.ning.http.client.filter.FilterException;
43 import com.ning.http.client.filter.ResponseFilter;
44 import com.terradue.jcatalogue.client.HttpMethod;
45 import com.terradue.jcatalogue.client.Parameter;
46
47
48
49
50 final class UmSsoStatusResponseFilter
51 implements ResponseFilter
52 {
53
54 private static final String SET_COOKIE = "Set-Cookie";
55
56 private static final String CONTENT_TYPE = "Content-Type";
57
58 private final Pattern textHtmlPattern = Pattern.compile( "text/html", CASE_INSENSITIVE );
59
60 private final BitSet admittedStatuses = new BitSet();
61
62 private final Logger logger = LoggerFactory.getLogger( getClass() );
63
64 private final Map<String, UmSsoAccess> umSsoCredentials;
65
66 private final ConcurrentMap<String, ConcurrentMap<String, Cookie>> cookiesRegistry;
67
68 public UmSsoStatusResponseFilter( ConcurrentMap<String, UmSsoAccess> umSsoCredentials,
69 ConcurrentMap<String, ConcurrentMap<String, Cookie>> cookiesRegistry)
70 {
71 this.umSsoCredentials = umSsoCredentials;
72 this.cookiesRegistry = cookiesRegistry;
73
74 admittedStatuses.set( HTTP_OK );
75 admittedStatuses.set( HTTP_MOVED_PERM );
76 admittedStatuses.set( HTTP_MOVED_TEMP );
77 admittedStatuses.set( 307 );
78 }
79
80 @Override
81 @SuppressWarnings( { "rawtypes", "unchecked" } )
82 public FilterContext filter( FilterContext ctx )
83 throws FilterException
84 {
85 HttpResponseStatus responseStatus = ctx.getResponseStatus();
86
87
88 checkState( admittedStatuses.get( responseStatus.getStatusCode() ),
89 "Impossible to query the catalog %s, server replied %s",
90 ctx.getRequest().getRawUrl(), responseStatus.getStatusText() );
91
92 final String currentDomain = URI.create( ctx.getRequest().getUrl() ).getHost();
93
94
95
96 final List<String> cookiesString = ctx.getResponseHeaders().getHeaders().get( SET_COOKIE );
97 final List<Cookie> cookies = new LinkedList<Cookie>();
98
99
100 if ( cookiesString == null || cookiesString.isEmpty() )
101 {
102 if ( logger.isDebugEnabled() )
103 {
104 logger.debug( "No cookies to manage in domain {}", currentDomain );
105 }
106 }
107 else
108 {
109
110 ConcurrentMap<String, Cookie> domainCookies = cookiesRegistry.get( currentDomain );
111 if ( domainCookies == null )
112 {
113 if ( logger.isDebugEnabled() )
114 {
115 logger.debug( "Domain {} was not already managed", currentDomain );
116 }
117
118
119 domainCookies = new ConcurrentHashMap<String, Cookie>();
120 cookiesRegistry.put( currentDomain, domainCookies );
121 }
122
123
124 for ( String cookieValue : cookiesString )
125 {
126 if ( logger.isDebugEnabled() )
127 {
128 logger.debug( "Received cookie {}", cookieValue );
129 }
130
131 Cookie currentCookie = parseCookie( cookieValue );
132
133 cookies.add( currentCookie );
134 domainCookies.put( currentCookie.getName(), currentCookie );
135 }
136 }
137
138 if ( logger.isDebugEnabled() )
139 {
140 logger.debug( "Checking server status code reply: {}", responseStatus.getStatusCode() );
141 }
142
143
144 if ( HTTP_OK == responseStatus.getStatusCode() )
145 {
146 String contentType = ctx.getResponseHeaders().getHeaders().getFirstValue( CONTENT_TYPE );
147
148 if ( logger.isDebugEnabled() )
149 {
150 logger.debug( "Checking content type {} behavior", contentType );
151 }
152
153 if ( !textHtmlPattern.matcher( contentType ).matches() )
154 {
155 logger.debug( "Content type {} doesn't ned to be analyzed, just proceed", contentType );
156
157
158 }
159
160 if ( logger.isDebugEnabled() )
161 {
162 logger.debug( "Checking UM-SSO auth credentials for current host {}", currentDomain );
163 }
164
165 UmSsoAccess umSsoAccess = umSsoCredentials.get( currentDomain );
166
167 if ( umSsoAccess != null )
168 {
169 if ( logger.isDebugEnabled() )
170 {
171 logger.debug( "Redirecting request to {} {}",
172 umSsoAccess.getHttpMethod(), umSsoAccess.getLoginFormUrl() );
173 }
174
175 RequestBuilder authRequestBuilder = new RequestBuilder( umSsoAccess.getHttpMethod().toString() )
176 .setUrl( umSsoAccess.getLoginFormUrl().toString() );
177
178 for ( Cookie cookie : cookiesRegistry.get( currentDomain ).values() )
179 {
180 if ( logger.isDebugEnabled() )
181 {
182 logger.debug( "Adding {} for host {}", cookie, currentDomain );
183 }
184
185 authRequestBuilder.addCookie( cookie );
186 }
187
188 for ( Parameter parameter : umSsoAccess.getParameters() )
189 {
190 authRequestBuilder.addParameter( parameter.getName(), parameter.getValue() );
191 }
192
193 return new FilterContext.FilterContextBuilder( ctx )
194 .request( authRequestBuilder.build() )
195 .asyncHandler( ctx.getAsyncHandler() )
196 .replayRequest( true )
197 .build();
198 }
199 else if ( logger.isWarnEnabled() )
200 {
201 logger.warn( "Domain {} not managed for UM-SSO authentication!", currentDomain );
202 }
203
204 return ctx;
205 }
206
207 if ( logger.isDebugEnabled() )
208 {
209 logger.debug( "Proceeding on serving the request" );
210 }
211
212 if ( HttpMethod.POST.toString().equals( ctx.getRequest().getMethod() ) )
213 {
214 RequestBuilder redirect = new RequestBuilder( ctx.getRequest() )
215 .setMethod( HttpMethod.GET.toString() );
216
217
218 for ( Cookie cookie : cookies )
219 {
220 redirect.addOrReplaceCookie( cookie );
221 }
222
223 return new FilterContext.FilterContextBuilder( ctx )
224 .request( redirect.build() )
225 .replayRequest( true )
226 .build();
227 }
228
229 return ctx;
230 }
231
232 }