Skip to content

Commit 5c2a70b

Browse files
committed
JCL-356: Prohibit weak authorization mechanisms
1 parent 9677e36 commit 5c2a70b

File tree

4 files changed

+191
-1
lines changed

4 files changed

+191
-1
lines changed

api/src/main/java/com/inrupt/client/auth/ReactiveAuthorization.java

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@
3434
import java.util.ServiceLoader;
3535
import java.util.Set;
3636
import java.util.TreeMap;
37+
import java.util.TreeSet;
3738
import java.util.concurrent.CompletableFuture;
3839
import java.util.concurrent.CompletionStage;
3940

@@ -64,9 +65,12 @@ public ReactiveAuthorization() {
6465
final ServiceLoader<AuthenticationProvider> loader = ServiceLoader.load(AuthenticationProvider.class,
6566
ReactiveAuthorization.class.getClassLoader());
6667

68+
final Set<String> prohibited = getProhibitedSchemes();
6769
for (final AuthenticationProvider provider : loader) {
6870
for (final String scheme : provider.getSchemes()) {
69-
registry.put(scheme, provider);
71+
if (!prohibited.contains(scheme)) {
72+
registry.put(scheme, provider);
73+
}
7074
}
7175
}
7276
}
@@ -117,5 +121,12 @@ static boolean sessionSupportsScheme(final Session session, final String scheme)
117121
}
118122
return session.supportedSchemes().contains(scheme);
119123
}
124+
125+
static Set<String> getProhibitedSchemes() {
126+
final Set<String> prohibited = new TreeSet<>(String.CASE_INSENSITIVE_ORDER);
127+
prohibited.add("Basic");
128+
prohibited.add("Digest");
129+
return prohibited;
130+
}
120131
}
121132

Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
/*
2+
* Copyright 2023 Inrupt Inc.
3+
*
4+
* Permission is hereby granted, free of charge, to any person obtaining a copy
5+
* of this software and associated documentation files (the "Software"), to deal in
6+
* the Software without restriction, including without limitation the rights to use,
7+
* copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the
8+
* Software, and to permit persons to whom the Software is furnished to do so,
9+
* subject to the following conditions:
10+
*
11+
* The above copyright notice and this permission notice shall be included in
12+
* all copies or substantial portions of the Software.
13+
*
14+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
15+
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
16+
* PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
17+
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
18+
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
19+
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
20+
*/
21+
package com.inrupt.client.auth;
22+
23+
import static java.nio.charset.StandardCharsets.UTF_8;
24+
25+
import com.inrupt.client.Request;
26+
import com.inrupt.client.spi.AuthenticationProvider;
27+
28+
import java.net.URI;
29+
import java.time.Instant;
30+
import java.util.Base64;
31+
import java.util.Collections;
32+
import java.util.Set;
33+
import java.util.concurrent.CompletableFuture;
34+
import java.util.concurrent.CompletionStage;
35+
36+
public class BasicAuthProvider implements AuthenticationProvider {
37+
38+
private static final String BASIC = "Basic";
39+
40+
@Override
41+
public String getScheme() {
42+
return BASIC;
43+
}
44+
45+
@Override
46+
public Set<String> getSchemes() {
47+
return Collections.singleton(BASIC);
48+
}
49+
50+
@Override
51+
public Authenticator getAuthenticator(final Challenge challenge) {
52+
return new BasicAuthenticator();
53+
}
54+
55+
public class BasicAuthenticator implements Authenticator {
56+
@Override
57+
public String getName() {
58+
return "BasicAuth";
59+
}
60+
61+
@Override
62+
public int getPriority() {
63+
return 100;
64+
}
65+
66+
@Override
67+
public CompletionStage<Credential> authenticate(final Session session, final Request request,
68+
final Set<String> algorithms) {
69+
final URI issuer = URI.create("https://issuer.test");
70+
final URI agent = URI.create("https://id.test/username");
71+
final Instant expiration = Instant.now().plusSeconds(300);
72+
final String token = Base64.getUrlEncoder().withoutPadding()
73+
.encodeToString("username:password".getBytes(UTF_8));
74+
return CompletableFuture.completedFuture(new Credential("Basic", issuer, token, expiration, agent, null));
75+
}
76+
}
77+
}
Lines changed: 101 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,101 @@
1+
/*
2+
* Copyright 2023 Inrupt Inc.
3+
*
4+
* Permission is hereby granted, free of charge, to any person obtaining a copy
5+
* of this software and associated documentation files (the "Software"), to deal in
6+
* the Software without restriction, including without limitation the rights to use,
7+
* copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the
8+
* Software, and to permit persons to whom the Software is furnished to do so,
9+
* subject to the following conditions:
10+
*
11+
* The above copyright notice and this permission notice shall be included in
12+
* all copies or substantial portions of the Software.
13+
*
14+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
15+
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
16+
* PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
17+
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
18+
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
19+
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
20+
*/
21+
package com.inrupt.client.auth;
22+
23+
import static org.junit.jupiter.api.Assertions.*;
24+
25+
import com.inrupt.client.Request;
26+
27+
import java.net.URI;
28+
import java.util.Collection;
29+
import java.util.Collections;
30+
import java.util.Optional;
31+
import java.util.Set;
32+
import java.util.UUID;
33+
import java.util.concurrent.CompletableFuture;
34+
import java.util.concurrent.CompletionStage;
35+
36+
import org.junit.jupiter.api.Test;
37+
38+
class ReactiveAuthorizationTest {
39+
40+
@Test
41+
void testProhibitedAuth() {
42+
final ReactiveAuthorization auth = new ReactiveAuthorization();
43+
final Session session = new BasicAuthSession();
44+
final Request req = Request.newBuilder(URI.create("https://storage.example")).build();
45+
final Optional<Credential> credential = auth.negotiate(session, req,
46+
Collections.singleton(Challenge.of("Basic"))).toCompletableFuture().join();
47+
assertFalse(credential.isPresent());
48+
}
49+
50+
static class BasicAuthSession implements Session {
51+
52+
@Override
53+
public String getId() {
54+
return UUID.randomUUID().toString();
55+
}
56+
57+
@Override
58+
public Optional<URI> getPrincipal() {
59+
return Optional.empty();
60+
}
61+
62+
@Override
63+
public Set<String> supportedSchemes() {
64+
return Collections.singleton("Basic");
65+
}
66+
67+
@Override
68+
public Optional<Credential> getCredential(final URI name, final URI uri) {
69+
return Optional.empty();
70+
}
71+
72+
@Override
73+
public Optional<Credential> fromCache(final Request request) {
74+
return Optional.empty();
75+
}
76+
77+
@Override
78+
public Optional<String> generateProof(final String jkt, final Request request) {
79+
return Optional.empty();
80+
}
81+
82+
@Override
83+
public Optional<String> selectThumbprint(final Collection<String> algorithms) {
84+
return Optional.empty();
85+
}
86+
87+
@Override
88+
public CompletionStage<Optional<Credential>> authenticate(final Authenticator authenticator,
89+
final Request request, final Set<String> algorithms) {
90+
return authenticator.authenticate(this, request, algorithms).thenApply(Optional::ofNullable);
91+
}
92+
93+
/* deprecated */
94+
@Override
95+
public CompletionStage<Optional<Credential>> authenticate(final Request request,
96+
final Set<String> algorithms) {
97+
return CompletableFuture.completedFuture(Optional.empty());
98+
}
99+
}
100+
101+
}
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
com.inrupt.client.auth.BasicAuthProvider

0 commit comments

Comments
 (0)