Skip to content

Commit 4ce331a

Browse files
add an example of basic user and group logic
* add failing test for demo purpose
1 parent c1da62f commit 4ce331a

File tree

4 files changed

+123
-11
lines changed

4 files changed

+123
-11
lines changed

jena-fuseki2/jena-fuseki-main/src/main/resources/org/apache/jena/fuseki/server/shiro.ini

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,10 +25,12 @@ user1=passwd1
2525

2626

2727
## If you want simple, basic authentication user/password
28-
## on the operations,
28+
## on the operations, where all authenticated users are authorized
2929
## 1 - set a better password in [users] above.
3030
## 2 - comment out the "/$/** = localhost" line and use:
31-
##/$/** = authcBasic,user[admin]
31+
##/$/** = authcBasic,user
32+
33+
##
3234

3335
## or to allow any access.
3436
##/$/** = anon

jena-fuseki2/jena-fuseki-main/src/test/java/org/apache/jena/fuseki/mod/shiro/TestModShiro.java

Lines changed: 104 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -21,15 +21,13 @@
2121

2222
package org.apache.jena.fuseki.mod.shiro;
2323

24-
import static org.junit.jupiter.api.Assertions.assertEquals;
25-
import static org.junit.jupiter.api.Assertions.assertNotNull;
26-
import static org.junit.jupiter.api.Assertions.assertThrows;
27-
2824
import java.net.Authenticator;
2925
import java.net.http.HttpClient;
3026

27+
import java.util.regex.Pattern;
3128
import org.junit.jupiter.api.AfterEach;
3229
import org.junit.jupiter.api.BeforeEach;
30+
import org.junit.jupiter.api.Disabled;
3331
import org.junit.jupiter.api.Test;
3432

3533
import org.apache.jena.atlas.lib.Lib;
@@ -52,6 +50,8 @@
5250
import org.apache.jena.sparql.exec.http.GSP;
5351
import org.apache.jena.sparql.exec.http.QueryExecHTTP;
5452

53+
import static org.junit.jupiter.api.Assertions.*;
54+
5555
public class TestModShiro {
5656
static final String unlocal = determineUnlocal();
5757
static final String localRE = "(localhost)|(127.0.0.1)|(::1)";
@@ -158,7 +158,7 @@ private FusekiServer.Builder serverBuilderWithShiro(String filename) {
158158
HttpClient httpClient = HttpEnv.httpClientBuilder().authenticator(authenticator).build();
159159
attemptByLocalhost(server, httpClient, dsname);
160160
// and a SPARQL query
161-
QueryExecHTTP.service(URL).httpClient(httpClient).query("ASK{}").ask();
161+
QueryExecHTTP.service(URL).httpClient(httpClient).query("ASK{}");
162162
}
163163

164164
// user-password via registration
@@ -168,17 +168,113 @@ private FusekiServer.Builder serverBuilderWithShiro(String filename) {
168168
AuthEnv.get().unregisterUsernamePassword(server.serverURL());
169169
}
170170

171-
// try the ping (proxy for admin operations)
171+
// try the ping (proxy for admin operations as admin user)
172+
Pattern startOfDateTimePattern = Pattern.compile("[0-9]{4}-.*");
172173
{
173174
Authenticator authenticator = AuthLib.authenticator("admin", "pw");
174175
HttpClient httpClient = HttpEnv.httpClientBuilder().authenticator(authenticator).build();
175-
HttpOp.httpGetString(httpClient, server.serverURL()+"$/ping");
176+
String pingResultString = HttpOp.httpGetString(httpClient, server.serverURL()+"$/ping");
177+
assertTrue(startOfDateTimePattern.matcher(pingResultString).find(),
178+
"admin user should be able to ping: " + pingResultString);
179+
AuthEnv.get().unregisterUsernamePassword(server.serverURL());
180+
}
181+
// try the ping (proxy for operations as user1 user without access)
182+
{
183+
// check that PingResult is still unauthorized
184+
HttpClient httpClientAnon = HttpEnv.httpClientBuilder().build();
185+
HttpException httpEx = assertThrows(HttpException.class, ()->HttpOp.httpGetString(httpClientAnon, server.serverURL()+"$/ping"));
186+
assertEquals(401, httpEx.getStatusCode(), "Expect HTTP 401 if not logged in");
187+
Authenticator authenticator = AuthLib.authenticator("user1", "passwd1");
188+
HttpClient httpClient = HttpEnv.httpClientBuilder().authenticator(authenticator).build();
189+
String pingResultString = HttpOp.httpGetString(httpClient, server.serverURL()+"$/ping");
190+
assertTrue(startOfDateTimePattern.matcher(pingResultString).find(),
191+
"user1 user should not be able to ping: " + pingResultString);
192+
}
193+
194+
195+
{
196+
// Bad password
197+
AuthEnv.get().registerUsernamePassword(server.serverURL(), "user1", "passwd2");
198+
HttpException httpEx = assertThrows(HttpException.class, ()->attemptByLocalhost(server, dsname));
199+
assertEquals(401, httpEx.getStatusCode(), "Expected HTTP 401");
200+
AuthEnv.get().unregisterUsernamePassword(server.serverURL());
201+
}
202+
203+
} finally {
204+
server.stop();
205+
}
206+
}
207+
208+
@Test public void access_userPassword_group() {
209+
String dsname = "/ds";
210+
DatasetGraph dsg = DatasetGraphFactory.createTxnMem();
211+
FusekiServer server = serverBuilderWithShiro("testing/Shiro/shiro_user_group_password.ini")
212+
.add(dsname, dsg)
213+
.enablePing(true)
214+
.build();
215+
server.start();
216+
217+
String URL = server.datasetURL(dsname);
218+
219+
try {
220+
// No user-password
221+
{
222+
HttpException httpEx = assertThrows(HttpException.class, ()->attemptByLocalhost(server, dsname));
223+
assertEquals(401, httpEx.getStatusCode(), "Expected HTTP 401");
224+
}
225+
226+
// user-password via authenticator: localhost
227+
{
228+
Authenticator authenticator = AuthLib.authenticator("user1", "passwd1");
229+
HttpClient httpClient = HttpEnv.httpClientBuilder().authenticator(authenticator).build();
230+
attemptByLocalhost(server, httpClient, dsname);
231+
// and a SPARQL query
232+
QueryExecHTTP.service(URL).httpClient(httpClient).query("ASK{}");
233+
}
234+
235+
// user-password via registration
236+
{
237+
AuthEnv.get().registerUsernamePassword(server.serverURL(), "user1", "passwd1");
238+
attemptByLocalhost(server, dsname);
176239
AuthEnv.get().unregisterUsernamePassword(server.serverURL());
177240
}
178241

242+
// try the ping (proxy for admin operations as admin user)
243+
Pattern startOfDateTimePattern = Pattern.compile("[0-9]{4}-.*");
244+
{
245+
Authenticator authenticator = AuthLib.authenticator("admin", "pw");
246+
HttpClient httpClient = HttpEnv.httpClientBuilder().authenticator(authenticator).build();
247+
String pingResultString = HttpOp.httpGetString(httpClient, server.serverURL()+"$/ping");
248+
assertTrue(startOfDateTimePattern.matcher(pingResultString).find(),
249+
"admin user should be able to ping: " + pingResultString);
250+
AuthEnv.get().unregisterUsernamePassword(server.serverURL());
251+
}
252+
// try the ping (proxy for operations as user1 user without access)
253+
{
254+
// check that PingResult is still unauthorized
255+
HttpClient httpClientAnon = HttpEnv.httpClientBuilder().build();
256+
HttpException httpEx = assertThrows(HttpException.class, ()->HttpOp.httpGetString(httpClientAnon, server.serverURL()+"$/ping"));
257+
assertEquals(401, httpEx.getStatusCode(), "Expect HTTP 401 if not logged in");
258+
Authenticator authenticator = AuthLib.authenticator("user1", "passwd1");
259+
HttpClient httpClient = HttpEnv.httpClientBuilder().authenticator(authenticator).build();
260+
// check again that the user is logged in and can access ds
261+
HttpOp.httpGetString(httpClient, server.datasetURL(dsname));
262+
System.out.println(server.serverURL()+ "$/ping");
263+
//String pingResultString = HttpOp.httpGetString(httpClient, server.serverURL()+"$/ping");
264+
//assertEquals(pingResultString, "OK", "PingResult: " + pingResultString);
265+
266+
// String pingResultString = HttpOp.httpGetString(httpClient, server.serverURL()+"$/ping");
267+
// assertEquals(pingResultString, "OK", "PingResult: " + pingResultString);
268+
HttpException httpEx2 = assertThrows(HttpException.class, ()->HttpOp.httpGetString(httpClient, server.serverURL()+"$/ping"));
269+
assertEquals(403, httpEx2.getStatusCode(), "Expect HTTP 403 if not logged in" + httpEx2.getResponse() + httpEx2.getMessage() + httpEx2.getStatusLine() + httpEx2.getStatusCode());
270+
271+
// assertFalse(startOfDateTimePattern.matcher(pingResultString).find(),
272+
// "user1 user should not be able to ping: " + pingResultString);
273+
}
179274
{
180275
// Bad password
181276
AuthEnv.get().registerUsernamePassword(server.serverURL(), "user1", "passwd2");
277+
// attemptByLocalhost(server, dsname);
182278
HttpException httpEx = assertThrows(HttpException.class, ()->attemptByLocalhost(server, dsname));
183279
assertEquals(401, httpEx.getStatusCode(), "Expected HTTP 401");
184280
AuthEnv.get().unregisterUsernamePassword(server.serverURL());
@@ -189,6 +285,7 @@ private FusekiServer.Builder serverBuilderWithShiro(String filename) {
189285
}
190286
}
191287

288+
192289
@Test public void shiroByCommandLine() {
193290
String dsname = "/ds";
194291
FusekiModule fmod = FMod_Shiro.create();

jena-fuseki2/jena-fuseki-main/src/test/resources/log4j2-test.properties

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -38,8 +38,8 @@ logger.http.level = INFO
3838
logger.riot.name = org.apache.jena.riot
3939
logger.riot.level = INFO
4040

41-
logger.riot.name = org.apache.shiro
42-
logger.riot.level = WARN
41+
logger.shiro.name = org.apache.shiro
42+
logger.shiro.level = DEBUG
4343

4444
logger.jetty.name = org.eclipse.jetty
4545
logger.jetty.level = WARN
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
# Licensed under the terms of http://www.apache.org/licenses/LICENSE-2.0
2+
3+
[main]
4+
plainMatcher=org.apache.shiro.authc.credential.SimpleCredentialsMatcher
5+
[users]
6+
admin=pw,admin
7+
user1=passwd1,user
8+
9+
[urls]
10+
/$/ping = authcBasic,roles[admin]
11+
/ds = authcBasic,roles[user]
12+
/$/stats = anon
13+
/** = anon

0 commit comments

Comments
 (0)