1
1
/*
2
- * Copyright (C) 2014 TopCoder Inc., All Rights Reserved.
2
+ * Copyright (C) 2014 - 2017 TopCoder Inc., All Rights Reserved.
3
3
*/
4
4
package com .topcoder .direct .services .view .action ;
5
5
6
6
import com .topcoder .direct .services .configs .ServerConfiguration ;
7
7
import com .topcoder .direct .services .view .dto .contest .ContestStatus ;
8
+ import com .topcoder .direct .services .view .dto .my .SingleRestResult ;
9
+ import com .topcoder .direct .services .view .dto .my .Token ;
8
10
import com .topcoder .direct .services .view .dto .project .ProjectBriefDTO ;
11
+ import com .topcoder .direct .services .view .exception .JwtAuthenticationException ;
9
12
import com .topcoder .direct .services .view .util .DataProvider ;
10
13
import com .topcoder .direct .services .view .util .DirectUtils ;
11
14
import com .topcoder .security .TCSubject ;
15
+ import org .apache .commons .codec .binary .Base64 ;
12
16
import org .apache .http .HttpEntity ;
13
17
import org .apache .http .HttpHeaders ;
14
18
import org .apache .http .HttpResponse ;
15
19
import org .apache .http .HttpStatus ;
16
20
import org .apache .http .client .methods .HttpGet ;
21
+ import org .apache .http .client .methods .HttpPost ;
17
22
import org .apache .http .client .utils .URIBuilder ;
23
+ import org .apache .http .entity .StringEntity ;
18
24
import org .apache .http .impl .client .DefaultHttpClient ;
19
25
import org .apache .log4j .Logger ;
20
26
import org .apache .struts2 .ServletActionContext ;
23
29
import org .codehaus .jackson .map .ObjectMapper ;
24
30
25
31
import javax .servlet .http .Cookie ;
32
+ import java .io .UnsupportedEncodingException ;
26
33
import java .net .URI ;
27
34
import java .net .URISyntaxException ;
35
+ import java .net .URLEncoder ;
36
+ import java .nio .charset .StandardCharsets ;
28
37
import java .text .SimpleDateFormat ;
29
- import java .util .ArrayList ;
30
- import java .util .LinkedHashMap ;
31
- import java .util .List ;
32
- import java .util .Map ;
38
+ import java .util .*;
33
39
34
40
/**
35
41
* <p>
@@ -102,6 +108,11 @@ public abstract class ServiceBackendDataTablesAction extends AbstractAction {
102
108
*/
103
109
private String serviceURL ;
104
110
111
+ /**
112
+ * authorization Url
113
+ */
114
+ private String authorizationURL ;
115
+
105
116
/**
106
117
* The challenge types options in filter panel
107
118
*
@@ -118,7 +129,6 @@ public abstract class ServiceBackendDataTablesAction extends AbstractAction {
118
129
119
130
/**
120
131
* The customer options in filter panel.
121
- *
122
132
* @since 1.1
123
133
*/
124
134
private Map <Long , String > customers ;
@@ -186,6 +196,11 @@ public abstract class ServiceBackendDataTablesAction extends AbstractAction {
186
196
*/
187
197
private String endDateTo ;
188
198
199
+ /**
200
+ * ssoLogin Url
201
+ */
202
+ private String ssoLoginUrl ;
203
+
189
204
/**
190
205
* The max pagination size.
191
206
*/
@@ -211,6 +226,11 @@ public abstract class ServiceBackendDataTablesAction extends AbstractAction {
211
226
*/
212
227
protected static final String ERROR_MESSAGE_FORMAT = "Service URL:%s, HTTP Status Code:%d, Error Message:%s" ;
213
228
229
+ /**
230
+ * URI params for refresh token
231
+ */
232
+ private final String AUTHORIZATION_PARAMS = "{\" param\" : {\" externalToken\" : \" %s\" }}" ;
233
+
214
234
/**
215
235
* The jackson object mapping which is used to deserialize json return from API to domain model.
216
236
*/
@@ -265,23 +285,29 @@ protected void setupFilterPanel() throws Exception {
265
285
* @return the built URI.
266
286
* @throws URISyntaxException if the syntax is error.
267
287
*/
268
- protected URI buildServiceEndPoint (Map <String , String > parameters ) throws URISyntaxException {
288
+ protected URI buildServiceEndPoint (Map <String , String > parameters ) throws URISyntaxException , UnsupportedEncodingException {
269
289
270
290
int pageSize = getiDisplayLength () == -1 ? MAX_PAGINATION_SIZE : getiDisplayLength ();
271
291
272
292
273
- URIBuilder builder = new URIBuilder ();
274
- builder . setScheme ( "http" ). setHost ( ServerConfiguration . DIRECT_API_SERVICE_ENDPOINT ). setPath ( getServiceURL ())
275
- .setParameter ("offset" , String .valueOf (getiDisplayStart ()))
293
+ URIBuilder builder = new URIBuilder (getServiceURL () );
294
+
295
+ builder .setParameter ("offset" , String .valueOf (getiDisplayStart ()))
276
296
.setParameter ("limit" , String .valueOf (pageSize ));
277
297
298
+ String filters = "" ;
278
299
if (parameters != null ) {
279
300
for (String key : parameters .keySet ()) {
280
- builder .setParameter (key , parameters .get (key ));
301
+ if ("filter" .equals (key )) {
302
+ filters = URLEncoder .encode (parameters .get (key ), "UTF-8" );
303
+ } else {
304
+ builder .setParameter (key , parameters .get (key ));
305
+ }
281
306
}
282
307
}
283
308
284
- return builder .build ();
309
+ return new URI (new StringBuilder (builder .build ().toString ()).append ("&filter=" ).append (filters ).toString ());
310
+
285
311
}
286
312
287
313
/**
@@ -313,23 +339,26 @@ protected JsonNode getJsonResultFromAPI(URI apiEndPoint) throws Exception {
313
339
// specify the get request
314
340
HttpGet getRequest = new HttpGet (apiEndPoint );
315
341
316
- Cookie jwtCookie = DirectUtils .getCookieFromRequest (ServletActionContext .getRequest (),
342
+ Cookie jwtCookieV3 = DirectUtils .getCookieFromRequest (ServletActionContext .getRequest (),
343
+ ServerConfiguration .JWT_V3_COOKIE_KEY );
344
+ Cookie jwtCookieV2 = DirectUtils .getCookieFromRequest (ServletActionContext .getRequest (),
317
345
ServerConfiguration .JWT_COOOKIE_KEY );
318
346
319
- if (jwtCookie == null ) {
320
- throw new Exception ( "The jwt cookie for the authorized user could not be loaded " );
347
+ if (jwtCookieV2 == null ) {
348
+ throw new JwtAuthenticationException ( "Please re-login " );
321
349
}
322
350
351
+ validateCookieV2V3 (jwtCookieV2 ,jwtCookieV3 );
352
+
323
353
getRequest .setHeader (HttpHeaders .AUTHORIZATION ,
324
- "Bearer " + jwtCookie .getValue ());
354
+ "Bearer " + jwtCookieV3 .getValue ());
325
355
326
356
getRequest .addHeader (HttpHeaders .ACCEPT , "application/json" );
327
357
328
358
HttpResponse httpResponse = httpClient .execute (getRequest );
329
359
HttpEntity entity = httpResponse .getEntity ();
330
360
331
361
if (httpResponse .getStatusLine ().getStatusCode () != HttpStatus .SC_OK ) {
332
-
333
362
throw new Exception (String .format (ERROR_MESSAGE_FORMAT ,
334
363
getRequest .getURI (),
335
364
httpResponse .getStatusLine ().getStatusCode (),
@@ -698,4 +727,144 @@ public String getEndDateTo() {
698
727
public void setEndDateTo (String endDateTo ) {
699
728
this .endDateTo = endDateTo ;
700
729
}
730
+
731
+ /**
732
+ * Getter for {@link #authorizationURL}
733
+ * @return authorizationURL
734
+ */
735
+ public String getAuthorizationURL () {
736
+ return authorizationURL ;
737
+ }
738
+
739
+ /**
740
+ * Setter for {@link #authorizationURL}
741
+ * @param authorizationURL
742
+ */
743
+ public void setAuthorizationURL (String authorizationURL ) {
744
+ this .authorizationURL = authorizationURL ;
745
+ }
746
+
747
+ /**
748
+ * Get Full SSO login url
749
+ * @return
750
+ */
751
+ public String getSsoLoginUrl () {
752
+ try {
753
+ URIBuilder builder = new URIBuilder (ssoLoginUrl );
754
+ builder .addParameter ("next" , ServletActionContext .getRequest ().getRequestURL ().toString ());
755
+ return builder .build ().toString ();
756
+ } catch (Exception e ) {
757
+ return ssoLoginUrl ;
758
+ }
759
+ }
760
+
761
+ /**
762
+ * Setter {@link #ssoLoginUrl}
763
+ *
764
+ * @param ssoLoginUrl
765
+ */
766
+ public void setSsoLoginUrl (String ssoLoginUrl ) {
767
+ this .ssoLoginUrl = ssoLoginUrl ;
768
+ }
769
+
770
+ /**
771
+ * Refresh token from API endpoint
772
+ *
773
+ * @param oldToken
774
+ * @return
775
+ * @throws Exception
776
+ */
777
+ private Token getRefreshTokenFromApi (String oldToken ) throws Exception {
778
+ DefaultHttpClient httpClient = new DefaultHttpClient ();
779
+ SingleRestResult <Token > resultToken = null ;
780
+ try {
781
+ URI authorizationUri = new URI (getAuthorizationURL ());
782
+ HttpPost httpPost = new HttpPost (authorizationUri );
783
+ httpPost .addHeader (HttpHeaders .CONTENT_TYPE , "application/json" );
784
+
785
+ StringEntity body = new StringEntity (String .format (AUTHORIZATION_PARAMS , oldToken ));
786
+ httpPost .setEntity (body );
787
+ HttpResponse response = httpClient .execute (httpPost );
788
+ HttpEntity entity = response .getEntity ();
789
+ if (response .getStatusLine ().getStatusCode () != HttpStatus .SC_OK ) {
790
+ throw new JwtAuthenticationException (String .format (ERROR_MESSAGE_FORMAT , authorizationUri ,
791
+ response .getStatusLine ().getStatusCode (),
792
+ getErrorMessage (response .getStatusLine ().getStatusCode ())));
793
+ }
794
+
795
+ JsonNode result = objectMapper .readTree (entity .getContent ());
796
+ resultToken = objectMapper .readValue (result .get ("result" ),
797
+ objectMapper .getTypeFactory ().constructParametricType (SingleRestResult .class , Token .class ));
798
+ } finally {
799
+ httpClient .getConnectionManager ().shutdown ();
800
+ }
801
+ return resultToken .getContent ();
802
+ }
803
+
804
+ /**
805
+ * Verify token.If token expired: refresh it
806
+ *
807
+ * @param tokenV3
808
+ * @param tokenV2
809
+ * @return
810
+ * @throws JwtAuthenticationException
811
+ */
812
+ private String getValidJwtToken (String tokenV3 , String tokenV2 ) throws JwtAuthenticationException {
813
+ String [] tokenSplit = tokenV3 .split ("\\ ." );
814
+ boolean valid = true ;
815
+ if (tokenSplit .length < 2 ) valid = false ;
816
+
817
+ JsonNode jsonNode = null ;
818
+
819
+ try {
820
+ if (valid ) {
821
+ StringBuffer payloadStr = new StringBuffer (tokenSplit [1 ]);
822
+ while (payloadStr .length () % 4 != 0 ) payloadStr .append ('=' );
823
+ String payload = new String (Base64 .decodeBase64 (payloadStr .toString ().getBytes (StandardCharsets .UTF_8 )));
824
+
825
+ jsonNode = objectMapper .readValue (payload .toString (), JsonNode .class );
826
+
827
+ long exp = jsonNode .get ("exp" ).getLongValue ();
828
+ Date expDate = new Date (exp * 1000 );
829
+ logger .info ("token expire: " + expDate );
830
+ if (expDate .before (new Date ())) valid = false ;
831
+ }
832
+
833
+ if (!valid ) {
834
+ logger .info ("refresh new token for : " + tokenV2 );
835
+ Token newToken = getRefreshTokenFromApi (tokenV2 );
836
+ if (newToken == null || newToken .getToken ().isEmpty ()) {
837
+ throw new JwtAuthenticationException ("Invalid refresh token" );
838
+ }
839
+
840
+ return newToken .getToken ();
841
+ }
842
+ } catch (Exception e ) {
843
+ throw new JwtAuthenticationException ("Failed to refresh toke through api, Please go to sso login page : " +
844
+ getSsoLoginUrl ());
845
+ }
846
+ return tokenV3 ;
847
+ }
848
+
849
+ /**
850
+ * Validate cookie v2 and v3
851
+ *
852
+ * @param v2 cookie v2
853
+ * @param v3 cookie v3
854
+ * @throws Exception
855
+ */
856
+ protected void validateCookieV2V3 (Cookie v2 , Cookie v3 ) throws Exception {
857
+ String validToken = null ;
858
+ String v3Token = null ;
859
+ if (v3 == null ) {
860
+ validToken = getRefreshTokenFromApi (v2 .getValue ()).getToken ();
861
+ } else {
862
+ validToken = getValidJwtToken (v3 .getValue (), v2 .getValue ());
863
+ v3Token = v3 .getValue ();
864
+ }
865
+
866
+ if (!validToken .equals (v3Token )) {
867
+ DirectUtils .addDirectCookie (ServletActionContext .getResponse (), ServerConfiguration .JWT_V3_COOKIE_KEY , validToken , -1 );
868
+ }
869
+ }
701
870
}
0 commit comments