1
1
package io .quarkus .resteasy .reactive .server .test .security ;
2
2
3
+ import static io .restassured .matcher .RestAssuredMatchers .detailedCookie ;
3
4
import static org .hamcrest .Matchers .containsString ;
5
+ import static org .hamcrest .Matchers .equalTo ;
6
+ import static org .hamcrest .Matchers .notNullValue ;
4
7
import static org .hamcrest .Matchers .nullValue ;
8
+ import static org .junit .jupiter .api .Assertions .assertNull ;
5
9
10
+ import java .net .URI ;
11
+ import java .time .Duration ;
6
12
import java .util .function .Supplier ;
7
13
14
+ import jakarta .enterprise .context .ApplicationScoped ;
15
+ import jakarta .ws .rs .GET ;
16
+ import jakarta .ws .rs .Path ;
17
+ import jakarta .ws .rs .core .Response ;
18
+
8
19
import org .jboss .shrinkwrap .api .ShrinkWrap ;
9
20
import org .jboss .shrinkwrap .api .asset .StringAsset ;
10
21
import org .jboss .shrinkwrap .api .spec .JavaArchive ;
22
+ import org .junit .jupiter .api .Assertions ;
11
23
import org .junit .jupiter .api .BeforeAll ;
12
24
import org .junit .jupiter .api .Test ;
13
25
import org .junit .jupiter .api .extension .RegisterExtension ;
14
26
27
+ import io .quarkus .security .Authenticated ;
28
+ import io .quarkus .security .UnauthorizedException ;
29
+ import io .quarkus .security .identity .AuthenticationRequestContext ;
30
+ import io .quarkus .security .identity .CurrentIdentityAssociation ;
31
+ import io .quarkus .security .identity .IdentityProvider ;
32
+ import io .quarkus .security .identity .SecurityIdentity ;
33
+ import io .quarkus .security .identity .request .TrustedAuthenticationRequest ;
34
+ import io .quarkus .security .runtime .QuarkusPrincipal ;
35
+ import io .quarkus .security .runtime .QuarkusSecurityIdentity ;
15
36
import io .quarkus .security .test .utils .TestIdentityController ;
16
37
import io .quarkus .security .test .utils .TestIdentityProvider ;
17
38
import io .quarkus .test .QuarkusUnitTest ;
39
+ import io .quarkus .vertx .http .runtime .security .FormAuthenticationMechanism ;
18
40
import io .restassured .RestAssured ;
19
41
import io .restassured .filter .cookie .CookieFilter ;
42
+ import io .smallrye .mutiny .Uni ;
20
43
21
44
public class FormAuthRedirectTestCase {
22
45
@@ -25,14 +48,21 @@ public class FormAuthRedirectTestCase {
25
48
@ Override
26
49
public JavaArchive get () {
27
50
return ShrinkWrap .create (JavaArchive .class )
28
- .addClasses (TestIdentityProvider .class , TestIdentityController .class )
29
- .addAsResource (new StringAsset ("quarkus.http.auth.form.enabled=true\n " ), "application.properties" );
51
+ .addClasses (TestIdentityProvider .class , TestIdentityController .class , FormAuthResource .class ,
52
+ TrustedIdentityProvider .class )
53
+ .addAsResource (new StringAsset ("""
54
+ quarkus.http.auth.form.enabled=true
55
+ quarkus.http.auth.form.landing-page=/hello
56
+ quarkus.http.auth.form.new-cookie-interval=PT1S
57
+ """ ), "application.properties" );
30
58
}
31
59
});
32
60
33
61
@ BeforeAll
34
62
public static void setup () {
35
- TestIdentityController .resetRoles ().add ("a d m i n" , "a d m i n" , "a d m i n" );
63
+ TestIdentityController .resetRoles ()
64
+ .add ("a d m i n" , "a d m i n" , "a d m i n" )
65
+ .add ("user" , "user" );
36
66
}
37
67
38
68
@ Test
@@ -53,4 +83,123 @@ public void testFormAuthFailure() {
53
83
.header ("quarkus-credential" , nullValue ());
54
84
}
55
85
86
+ @ Test
87
+ public void testFormAuthLoginLogout () throws InterruptedException {
88
+ RestAssured .enableLoggingOfRequestAndResponseIfValidationFails ();
89
+ CookieFilter cookies = new CookieFilter ();
90
+ var response = RestAssured
91
+ .given ()
92
+ .filter (cookies )
93
+ .redirects ().follow (false )
94
+ .when ()
95
+ .get ("/hello" )
96
+ .then ()
97
+ .assertThat ()
98
+ .statusCode (302 )
99
+ .header ("location" , containsString ("/login.html" ))
100
+ .extract ();
101
+ assertNull (response .cookie ("quarkus-credential" ));
102
+
103
+ RestAssured
104
+ .given ()
105
+ .filter (cookies )
106
+ .redirects ().follow (false )
107
+ .when ()
108
+ .formParam ("j_username" , "user" )
109
+ .formParam ("j_password" , "user" )
110
+ .post ("/j_security_check" )
111
+ .then ()
112
+ .assertThat ()
113
+ .statusCode (302 )
114
+ .header ("location" , containsString ("/hello" ))
115
+ .cookie ("quarkus-credential" , detailedCookie ().value (notNullValue ()).sameSite ("Strict" ).path ("/" ));
116
+
117
+ RestAssured
118
+ .given ()
119
+ .filter (cookies )
120
+ .redirects ().follow (false )
121
+ .when ()
122
+ .get ("/hello" )
123
+ .then ()
124
+ .assertThat ()
125
+ .statusCode (200 )
126
+ .body (equalTo ("hello user" ));
127
+
128
+ Thread .sleep (Duration .ofSeconds (2 ).toMillis ());
129
+
130
+ response = RestAssured
131
+ .given ()
132
+ .filter (cookies )
133
+ .redirects ().follow (false )
134
+ .when ()
135
+ .get ("/logout" )
136
+ .then ()
137
+ .assertThat ()
138
+ .statusCode (303 )
139
+ .header ("location" , containsString ("/" ))
140
+ .extract ();
141
+ String credentialsCookieValue = response .cookie ("quarkus-credential" );
142
+ Assertions .assertTrue (credentialsCookieValue == null || credentialsCookieValue .isEmpty (),
143
+ "Expected credentials cookie was removed, but actual value was " + credentialsCookieValue );
144
+
145
+ response = RestAssured
146
+ .given ()
147
+ .filter (cookies )
148
+ .redirects ().follow (false )
149
+ .when ()
150
+ .get ("/hello" )
151
+ .then ()
152
+ .assertThat ()
153
+ .statusCode (302 )
154
+ .header ("location" , containsString ("/login.html" ))
155
+ .extract ();
156
+ credentialsCookieValue = response .cookie ("quarkus-credential" );
157
+ Assertions .assertTrue (credentialsCookieValue == null || credentialsCookieValue .isEmpty ());
158
+ }
159
+
160
+ @ Path ("/" )
161
+ public static class FormAuthResource {
162
+
163
+ private final CurrentIdentityAssociation identity ;
164
+
165
+ public FormAuthResource (CurrentIdentityAssociation identity ) {
166
+ this .identity = identity ;
167
+ }
168
+
169
+ @ Authenticated
170
+ @ GET
171
+ @ Path ("hello" )
172
+ public String hello () {
173
+ return "hello " + identity .getIdentity ().getPrincipal ().getName ();
174
+ }
175
+
176
+ @ GET
177
+ @ Path ("logout" )
178
+ public Response logout () {
179
+ if (identity .getIdentity ().isAnonymous ()) {
180
+ throw new UnauthorizedException ("Not authenticated" );
181
+ }
182
+ FormAuthenticationMechanism .logout (identity .getIdentity ());
183
+ return Response .seeOther (URI .create ("/" ))
184
+ .build ();
185
+ }
186
+ }
187
+
188
+ @ ApplicationScoped
189
+ public static class TrustedIdentityProvider implements IdentityProvider <TrustedAuthenticationRequest > {
190
+ @ Override
191
+ public Class <TrustedAuthenticationRequest > getRequestType () {
192
+ return TrustedAuthenticationRequest .class ;
193
+ }
194
+
195
+ @ Override
196
+ public Uni <SecurityIdentity > authenticate (TrustedAuthenticationRequest trustedAuthenticationRequest ,
197
+ AuthenticationRequestContext authenticationRequestContext ) {
198
+ if ("user" .equals (trustedAuthenticationRequest .getPrincipal ())) {
199
+ return Uni .createFrom ()
200
+ .item (QuarkusSecurityIdentity .builder ().setPrincipal (new QuarkusPrincipal ("user" )).build ());
201
+ }
202
+ return Uni .createFrom ().nullItem ();
203
+ }
204
+ }
56
205
}
0 commit comments