1
1
package org .lowcoder .api .framework .filter ;
2
2
3
3
import lombok .extern .slf4j .Slf4j ;
4
+ import org .apache .commons .lang3 .tuple .Triple ;
4
5
import org .lowcoder .api .authentication .request .AuthRequest ;
5
6
import org .lowcoder .api .authentication .request .AuthRequestFactory ;
6
7
import org .lowcoder .api .authentication .request .oauth2 .OAuth2RequestContext ;
7
8
import org .lowcoder .api .authentication .service .AuthenticationApiServiceImpl ;
8
9
import org .lowcoder .api .home .SessionUserService ;
9
10
import org .lowcoder .domain .authentication .AuthenticationService ;
10
- import org .lowcoder .domain .authentication .FindAuthConfig ;
11
11
import org .lowcoder .domain .authentication .context .AuthRequestContext ;
12
12
import org .lowcoder .domain .user .model .AuthUser ;
13
+ import org .lowcoder .domain .user .model .Connection ;
14
+ import org .lowcoder .domain .user .model .User ;
15
+ import org .lowcoder .domain .user .service .UserService ;
13
16
import org .lowcoder .sdk .util .CookieHelper ;
14
17
import org .springframework .web .server .ServerWebExchange ;
15
18
import org .springframework .web .server .WebFilter ;
18
21
19
22
import javax .annotation .Nonnull ;
20
23
import java .time .Instant ;
21
- import java .util .LinkedList ;
22
- import java .util .List ;
24
+ import java .util .Optional ;
23
25
24
26
import static org .lowcoder .api .authentication .util .AuthenticationUtils .toAuthentication ;
25
27
import static org .lowcoder .domain .authentication .AuthenticationService .DEFAULT_AUTH_CONFIG ;
29
31
public class UserSessionPersistenceFilter implements WebFilter {
30
32
31
33
private final SessionUserService service ;
34
+
35
+ private final UserService userService ;
32
36
private final CookieHelper cookieHelper ;
33
37
34
38
private final AuthenticationService authenticationService ;
@@ -37,9 +41,10 @@ public class UserSessionPersistenceFilter implements WebFilter {
37
41
38
42
private final AuthRequestFactory <AuthRequestContext > authRequestFactory ;
39
43
40
- public UserSessionPersistenceFilter (SessionUserService service , CookieHelper cookieHelper , AuthenticationService authenticationService ,
44
+ public UserSessionPersistenceFilter (SessionUserService service , UserService userService , CookieHelper cookieHelper , AuthenticationService authenticationService ,
41
45
AuthenticationApiServiceImpl authenticationApiService , AuthRequestFactory <AuthRequestContext > authRequestFactory ) {
42
46
this .service = service ;
47
+ this .userService = userService ;
43
48
this .cookieHelper = cookieHelper ;
44
49
this .authenticationService = authenticationService ;
45
50
this .authenticationApiService = authenticationApiService ;
@@ -52,48 +57,88 @@ public Mono<Void> filter(@Nonnull ServerWebExchange exchange, WebFilterChain cha
52
57
String cookieToken = cookieHelper .getCookieToken (exchange );
53
58
return service .resolveSessionUserFromCookie (cookieToken )
54
59
.switchIfEmpty (chain .filter (exchange ).then (Mono .empty ()))
55
- .doOnNext (user -> {
60
+ .map (user -> {
56
61
57
- List <String > tokensToRemove = new LinkedList <>();
62
+ Connection activeConnection = null ;
63
+ String orgId = null ;
58
64
59
- user .getConnections ().forEach (connection -> {
60
- if (!connection .getAuthId ().equals (DEFAULT_AUTH_CONFIG .getId ())) {
61
- Instant next5Minutes = Instant .now ().plusSeconds ( 300 );
62
- if (connection .getAuthConnectionAuthToken ().getExpireAt () == 0 ) {
63
- return ;
64
- }
65
- boolean isAccessTokenExpiryNear = (connection .getAuthConnectionAuthToken ().getExpireAt ()*1000 ) <= next5Minutes .toEpochMilli ();
66
- if (isAccessTokenExpiryNear ) {
67
- connection .getOrgIds ().forEach (orgId -> {
68
- authenticationService .findAuthConfigByAuthId (orgId , connection .getAuthId ())
69
- .doOnSuccess (findAuthConfig -> {
70
- if (findAuthConfig == null ) {
71
- return ;
72
- }
73
- OAuth2RequestContext oAuth2RequestContext = new OAuth2RequestContext (orgId , null , null );
74
- oAuth2RequestContext .setAuthConfig (findAuthConfig .authConfig ());
75
- AuthRequest authRequest = authRequestFactory .build (oAuth2RequestContext ).block ();
76
- try {
77
- AuthUser authUser = authRequest .refresh (connection .getAuthConnectionAuthToken ().getRefreshToken ()).block ();
78
- authUser .setAuthContext (oAuth2RequestContext );
79
- authenticationApiService .updateConnection (authUser , user );
80
- } catch (Exception e ) {
81
- log .error ("Failed to refresh access token. Removing user sessions/tokens." );
82
- tokensToRemove .addAll (connection .getTokens ());
83
- }
84
- });
85
- });
65
+ Optional <Connection > activeConnectionOptional = user .getConnections ()
66
+ .stream ()
67
+ .filter (connection -> connection .getAuthId ().equals (user .getActiveAuthId ()))
68
+ .findFirst ();
69
+
70
+ if (!activeConnectionOptional .isPresent ()) {
71
+ return Triple .of (user , activeConnection , orgId );
72
+ }
73
+
74
+ activeConnection = activeConnectionOptional .get ();
75
+
76
+ if (!activeConnection .getAuthId ().equals (DEFAULT_AUTH_CONFIG .getId ())) {
77
+ if (activeConnection .getAuthConnectionAuthToken ().getExpireAt () == 0 ) {
78
+ return Triple .of (user , activeConnection , orgId );
79
+ }
80
+ boolean isAccessTokenExpired = (activeConnection .getAuthConnectionAuthToken ().getExpireAt ()*1000 ) < Instant .now ().toEpochMilli ();
81
+ if (isAccessTokenExpired ) {
82
+
83
+ Optional <String > orgIdOptional = activeConnection .getOrgIds ().stream ().findFirst ();
84
+ if (!orgIdOptional .isPresent ()) {
85
+ return Triple .of (user , activeConnection , orgId );
86
86
}
87
+ orgId = orgIdOptional .get ();
87
88
}
88
- });
89
+ }
89
90
90
- tokensToRemove .forEach (token -> {
91
- service .removeUserSession (token ).block ();
92
- });
91
+ return Triple .of (user , activeConnection , orgId );
93
92
94
- })
93
+ }). flatMap ( this :: refreshOauthToken )
95
94
.flatMap (user -> chain .filter (exchange ).contextWrite (withAuthentication (toAuthentication (user )))
96
95
.then (service .extendValidity (cookieToken ))
97
96
);
98
97
}
98
+
99
+ private Mono <User > refreshOauthToken (Triple <User , Connection , String > triple ) {
100
+
101
+ User user = triple .getLeft ();
102
+ Connection connection = triple .getMiddle ();
103
+ String orgId = triple .getRight ();
104
+
105
+ if (connection == null || orgId == null ) {
106
+ return Mono .just (user );
107
+ }
108
+
109
+ OAuth2RequestContext oAuth2RequestContext = new OAuth2RequestContext (triple .getRight (), null , null );
110
+
111
+ return authenticationService
112
+ .findAuthConfigByAuthId (orgId , connection .getAuthId ())
113
+ .switchIfEmpty (Mono .empty ())
114
+ .flatMap (findAuthConfig -> {
115
+
116
+ Mono <AuthRequest > authRequestMono = Mono .empty ();
117
+
118
+ if (findAuthConfig == null ) {
119
+ return authRequestMono ;
120
+ }
121
+ oAuth2RequestContext .setAuthConfig (findAuthConfig .authConfig ());
122
+
123
+ return authRequestFactory .build (oAuth2RequestContext );
124
+ }).flatMap (authRequest -> {
125
+ if (authRequest == null ) {
126
+ return Mono .just (user );
127
+ }
128
+ try {
129
+ AuthUser authUser = authRequest .refresh (connection .getAuthConnectionAuthToken ().getRefreshToken ()).block ();
130
+ authUser .setAuthContext (oAuth2RequestContext );
131
+ authenticationApiService .updateConnection (authUser , user );
132
+ return userService .update (user .getId (), user );
133
+ } catch (Exception e ) {
134
+ log .error ("Failed to refresh access token. Removing user sessions/tokens." );
135
+ connection .getTokens ().forEach (token -> {
136
+ service .removeUserSession (token ).block ();
137
+ });
138
+ }
139
+ return Mono .just (user );
140
+ });
141
+
142
+ }
143
+
99
144
}
0 commit comments