Skip to content

Commit

Permalink
Encode clientId and clientSecret
Browse files Browse the repository at this point in the history
  • Loading branch information
ngocnhan-tran1996 committed Oct 29, 2024
1 parent 1782668 commit 9f52814
Show file tree
Hide file tree
Showing 8 changed files with 120 additions and 8 deletions.
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2021 the original author or authors.
* Copyright 2002-2024 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
Expand All @@ -17,6 +17,8 @@
package org.springframework.security.oauth2.server.resource.introspection;

import java.net.URI;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.time.Instant;
import java.util.ArrayList;
import java.util.Collection;
Expand Down Expand Up @@ -82,8 +84,10 @@ public NimbusOpaqueTokenIntrospector(String introspectionUri, String clientId, S
Assert.notNull(clientId, "clientId cannot be null");
Assert.notNull(clientSecret, "clientSecret cannot be null");
this.requestEntityConverter = this.defaultRequestEntityConverter(URI.create(introspectionUri));
String encodeClientId = URLEncoder.encode(clientId, StandardCharsets.UTF_8);
String encodeClientSecret = URLEncoder.encode(clientSecret, StandardCharsets.UTF_8);
RestTemplate restTemplate = new RestTemplate();
restTemplate.getInterceptors().add(new BasicAuthenticationInterceptor(clientId, clientSecret));
restTemplate.getInterceptors().add(new BasicAuthenticationInterceptor(encodeClientId, encodeClientSecret));
this.restOperations = restTemplate;
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2021 the original author or authors.
* Copyright 2002-2024 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
Expand All @@ -17,6 +17,8 @@
package org.springframework.security.oauth2.server.resource.introspection;

import java.net.URI;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.time.Instant;
import java.util.ArrayList;
import java.util.Collection;
Expand Down Expand Up @@ -79,7 +81,11 @@ public NimbusReactiveOpaqueTokenIntrospector(String introspectionUri, String cli
Assert.hasText(clientId, "clientId cannot be empty");
Assert.notNull(clientSecret, "clientSecret cannot be null");
this.introspectionUri = URI.create(introspectionUri);
this.webClient = WebClient.builder().defaultHeaders((h) -> h.setBasicAuth(clientId, clientSecret)).build();
String encodeClientId = URLEncoder.encode(clientId, StandardCharsets.UTF_8);
String encodeClientSecret = URLEncoder.encode(clientSecret, StandardCharsets.UTF_8);
this.webClient = WebClient.builder()
.defaultHeaders((h) -> h.setBasicAuth(encodeClientId, encodeClientSecret))
.build();
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@
package org.springframework.security.oauth2.server.resource.introspection;

import java.net.URI;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.time.Instant;
import java.util.ArrayList;
import java.util.Arrays;
Expand Down Expand Up @@ -84,8 +86,10 @@ public SpringOpaqueTokenIntrospector(String introspectionUri, String clientId, S
Assert.notNull(clientId, "clientId cannot be null");
Assert.notNull(clientSecret, "clientSecret cannot be null");
this.requestEntityConverter = this.defaultRequestEntityConverter(URI.create(introspectionUri));
String encodeClientId = URLEncoder.encode(clientId, StandardCharsets.UTF_8);
String encodeClientSecret = URLEncoder.encode(clientSecret, StandardCharsets.UTF_8);
RestTemplate restTemplate = new RestTemplate();
restTemplate.getInterceptors().add(new BasicAuthenticationInterceptor(clientId, clientSecret));
restTemplate.getInterceptors().add(new BasicAuthenticationInterceptor(encodeClientId, encodeClientSecret));
this.restOperations = restTemplate;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@
package org.springframework.security.oauth2.server.resource.introspection;

import java.net.URI;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.time.Instant;
import java.util.ArrayList;
import java.util.Arrays;
Expand Down Expand Up @@ -79,7 +81,11 @@ public SpringReactiveOpaqueTokenIntrospector(String introspectionUri, String cli
Assert.hasText(clientId, "clientId cannot be empty");
Assert.notNull(clientSecret, "clientSecret cannot be null");
this.introspectionUri = URI.create(introspectionUri);
this.webClient = WebClient.builder().defaultHeaders((h) -> h.setBasicAuth(clientId, clientSecret)).build();
String encodeClientId = URLEncoder.encode(clientId, StandardCharsets.UTF_8);
String encodeClientSecret = URLEncoder.encode(clientSecret, StandardCharsets.UTF_8);
this.webClient = WebClient.builder()
.defaultHeaders((h) -> h.setBasicAuth(encodeClientId, encodeClientSecret))
.build();
}

/**
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2021 the original author or authors.
* Copyright 2002-2024 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
Expand Down Expand Up @@ -343,6 +343,29 @@ public void handleNonJsonContentType(String type) {
.isThrownBy(() -> introspectionClient.introspect("sometokenhere"));
}

@Test
public void encodeUsernameAndPassword() throws Exception {
try (MockWebServer server = new MockWebServer()) {
String response = """
{
"active": true,
"username": "client%&1"
}
""";
server.setDispatcher(requiresAuth("client%25%261", "secret%40%242", response));
String introspectUri = server.url("/introspect").toString();
OpaqueTokenIntrospector introspectionClient = new NimbusOpaqueTokenIntrospector(introspectUri, "client%&1",
"secret@$2");
OAuth2AuthenticatedPrincipal authority = introspectionClient.introspect("token");
// @formatter:off
assertThat(authority.getAttributes())
.isNotNull()
.containsEntry(OAuth2TokenIntrospectionClaimNames.ACTIVE, true)
.containsEntry(OAuth2TokenIntrospectionClaimNames.USERNAME, "client%&1");
// @formatter:on
}
}

private static ResponseEntity<String> response(String content) {
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_JSON);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2021 the original author or authors.
* Copyright 2002-2024 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
Expand Down Expand Up @@ -260,6 +260,29 @@ public void handleNonJsonContentType(String type) {
.isThrownBy(() -> introspectionClient.introspect("sometokenhere").block());
}

@Test
public void encodeUsernameAndPassword() throws Exception {
try (MockWebServer server = new MockWebServer()) {
String response = """
{
"active": true,
"username": "client%&1"
}
""";
server.setDispatcher(requiresAuth("client%25%261", "secret%40%242", response));
String introspectUri = server.url("/introspect").toString();
ReactiveOpaqueTokenIntrospector introspectionClient = new NimbusReactiveOpaqueTokenIntrospector(
introspectUri, "client%&1", "secret@$2");
OAuth2AuthenticatedPrincipal authority = introspectionClient.introspect("token").block();
// @formatter:off
assertThat(authority.getAttributes())
.isNotNull()
.containsEntry(OAuth2TokenIntrospectionClaimNames.ACTIVE, true)
.containsEntry(OAuth2TokenIntrospectionClaimNames.USERNAME, "client%&1");
// @formatter:on
}
}

private WebClient mockResponse(String response) {
return mockResponse(response, MediaType.APPLICATION_JSON_VALUE);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -339,6 +339,29 @@ public void setAuthenticationConverterWhenNonNullConverterGivenThenConverterUsed
verify(authenticationConverter).convert(any());
}

@Test
public void encodeUsernameAndPassword() throws Exception {
try (MockWebServer server = new MockWebServer()) {
String response = """
{
"active": true,
"username": "client%&1"
}
""";
server.setDispatcher(requiresAuth("client%25%261", "secret%40%242", response));
String introspectUri = server.url("/introspect").toString();
OpaqueTokenIntrospector introspectionClient = new SpringOpaqueTokenIntrospector(introspectUri, "client%&1",
"secret@$2");
OAuth2AuthenticatedPrincipal authority = introspectionClient.introspect("token");
// @formatter:off
assertThat(authority.getAttributes())
.isNotNull()
.containsEntry(OAuth2TokenIntrospectionClaimNames.ACTIVE, true)
.containsEntry(OAuth2TokenIntrospectionClaimNames.USERNAME, "client%&1");
// @formatter:on
}
}

private static ResponseEntity<Map<String, Object>> response(String content) {
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_JSON);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -261,6 +261,29 @@ public void constructorWhenRestOperationsIsNullThenIllegalArgumentException() {
.isThrownBy(() -> new SpringReactiveOpaqueTokenIntrospector(INTROSPECTION_URL, null));
}

@Test
public void encodeUsernameAndPassword() throws Exception {
try (MockWebServer server = new MockWebServer()) {
String response = """
{
"active": true,
"username": "client%&1"
}
""";
server.setDispatcher(requiresAuth("client%25%261", "secret%40%242", response));
String introspectUri = server.url("/introspect").toString();
ReactiveOpaqueTokenIntrospector introspectionClient = new SpringReactiveOpaqueTokenIntrospector(
introspectUri, "client%&1", "secret@$2");
OAuth2AuthenticatedPrincipal authority = introspectionClient.introspect("token").block();
// @formatter:off
assertThat(authority.getAttributes())
.isNotNull()
.containsEntry(OAuth2TokenIntrospectionClaimNames.ACTIVE, true)
.containsEntry(OAuth2TokenIntrospectionClaimNames.USERNAME, "client%&1");
// @formatter:on
}
}

private WebClient mockResponse(String response) {
return mockResponse(toMap(response));
}
Expand Down

0 comments on commit 9f52814

Please sign in to comment.