mirror of
https://github.com/spring-projects/spring-security.git
synced 2026-03-05 03:04:31 +00:00
Move Snippets to Compiled Code
Issue gh-18745 Signed-off-by: Josh Cummings <3627351+jzheaux@users.noreply.github.com>
This commit is contained in:
parent
498b0cb59c
commit
587ac2cbad
@ -533,7 +533,7 @@ Or, exposing a <<oauth2resourceserver-opaque-architecture-introspector,`OpaqueTo
|
||||
----
|
||||
@Bean
|
||||
public OpaqueTokenIntrospector introspector() {
|
||||
return return SpringOpaqueTokenIntrospector.withIntrospectionUri(introspectionUri)
|
||||
return SpringOpaqueTokenIntrospector.withIntrospectionUri(introspectionUri)
|
||||
.clientId(clientId).clientSecret(clientSecret).build();
|
||||
}
|
||||
----
|
||||
@ -754,82 +754,28 @@ By default, Resource Server uses connection and socket timeouts of 30 seconds ea
|
||||
This may be too short in some scenarios.
|
||||
Further, it doesn't take into account more sophisticated patterns like back-off and discovery.
|
||||
|
||||
To adjust the way in which Resource Server connects to the authorization server, `SpringOpaqueTokenIntrospector` accepts an instance of `RestOperations`:
|
||||
|
||||
[tabs]
|
||||
======
|
||||
Java::
|
||||
+
|
||||
[source,java,role="primary"]
|
||||
----
|
||||
@Bean
|
||||
public OpaqueTokenIntrospector introspector(RestTemplateBuilder builder, OAuth2ResourceServerProperties properties) {
|
||||
RestOperations rest = builder
|
||||
.basicAuthentication(properties.getOpaquetoken().getClientId(), properties.getOpaquetoken().getClientSecret())
|
||||
.setConnectTimeout(Duration.ofSeconds(60))
|
||||
.setReadTimeout(Duration.ofSeconds(60))
|
||||
.build();
|
||||
|
||||
return new SpringOpaqueTokenIntrospector(introspectionUri, rest);
|
||||
}
|
||||
----
|
||||
|
||||
Kotlin::
|
||||
+
|
||||
[source,kotlin,role="secondary"]
|
||||
----
|
||||
@Bean
|
||||
fun introspector(builder: RestTemplateBuilder, properties: OAuth2ResourceServerProperties): OpaqueTokenIntrospector? {
|
||||
val rest: RestOperations = builder
|
||||
.basicAuthentication(properties.opaquetoken.clientId, properties.opaquetoken.clientSecret)
|
||||
.setConnectTimeout(Duration.ofSeconds(60))
|
||||
.setReadTimeout(Duration.ofSeconds(60))
|
||||
.build()
|
||||
return SpringOpaqueTokenIntrospector(introspectionUri, rest)
|
||||
}
|
||||
----
|
||||
======
|
||||
|
||||
[[oauth2resourceserver-opaque-restclient]]
|
||||
[[opaque-token-timeouts-rest-client]]
|
||||
=== Using `RestClientOpaqueTokenIntrospector`
|
||||
|
||||
Alternatively, you can use `RestClientOpaqueTokenIntrospector`, which uses `RestClient` instead of `RestTemplate`.
|
||||
This allows using the same configuration while benefiting from the newer `RestClient` API.
|
||||
You can use `RestClientOpaqueTokenIntrospector`, which uses `RestClient` to communicate with the introspection endpoint.
|
||||
|
||||
[tabs]
|
||||
======
|
||||
Java::
|
||||
+
|
||||
[source,java,role="primary"]
|
||||
----
|
||||
@Bean
|
||||
public OpaqueTokenIntrospector introspector(RestTemplateBuilder builder, OAuth2ResourceServerProperties properties) {
|
||||
RestTemplate restTemplate = builder
|
||||
.basicAuthentication(properties.getOpaquetoken().getClientId(), properties.getOpaquetoken().getClientSecret())
|
||||
.connectTimeout(Duration.ofSeconds(60))
|
||||
.readTimeout(Duration.ofSeconds(60))
|
||||
.build();
|
||||
RestClient restClient = RestClient.create(restTemplate);
|
||||
return new RestClientOpaqueTokenIntrospector(introspectionUri, restClient);
|
||||
}
|
||||
----
|
||||
[TIP]
|
||||
====
|
||||
When using Spring Boot, you can inject `OAuth2ResourceServerProperties` to obtain the introspection URI and client credentials.
|
||||
====
|
||||
|
||||
Kotlin::
|
||||
+
|
||||
[source,kotlin,role="secondary"]
|
||||
----
|
||||
@Bean
|
||||
fun introspector(builder: RestTemplateBuilder, properties: OAuth2ResourceServerProperties): OpaqueTokenIntrospector {
|
||||
val restTemplate = builder
|
||||
.basicAuthentication(properties.opaquetoken.clientId, properties.opaquetoken.clientSecret)
|
||||
.connectTimeout(Duration.ofSeconds(60))
|
||||
.readTimeout(Duration.ofSeconds(60))
|
||||
.build()
|
||||
val restClient = RestClient.create(restTemplate)
|
||||
return RestClientOpaqueTokenIntrospector(introspectionUri, restClient)
|
||||
}
|
||||
----
|
||||
======
|
||||
.Minimal configuration using the builder
|
||||
include-code::./RestClientOpaqueTokenIntrospectorConfiguration[tag=restclient-simple,indent=0]
|
||||
|
||||
To customize timeouts, build a `RestClient` with a custom `RequestFactory` and pass it to the introspector:
|
||||
|
||||
.Custom timeouts
|
||||
include-code::./RestClientOpaqueTokenIntrospectorConfiguration[tag=restclient-timeouts,indent=0]
|
||||
|
||||
[TIP]
|
||||
====
|
||||
If you prefer to use `RestTemplate`, you can use `SpringOpaqueTokenIntrospector` instead, which accepts an instance of `RestOperations`.
|
||||
====
|
||||
|
||||
[[oauth2resourceserver-opaque-jwt-introspector]]
|
||||
== Using Introspection with JWTs
|
||||
|
||||
@ -42,6 +42,7 @@ dependencies {
|
||||
testImplementation project(path : ':spring-security-config', configuration : 'tests')
|
||||
testImplementation project(':spring-security-test')
|
||||
testImplementation project(':spring-security-oauth2-client')
|
||||
testImplementation project(':spring-security-oauth2-resource-server')
|
||||
testImplementation 'com.squareup.okhttp3:mockwebserver'
|
||||
testImplementation libs.com.password4j.password4j
|
||||
testImplementation 'com.unboundid:unboundid-ldapsdk'
|
||||
|
||||
@ -0,0 +1,56 @@
|
||||
/*
|
||||
* Copyright 2004-present 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.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.security.docs.servlet.oauth2.resourceserver.opaquetokentimeoutsrestclient;
|
||||
|
||||
import java.time.Duration;
|
||||
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.http.client.SimpleClientHttpRequestFactory;
|
||||
import org.springframework.security.oauth2.server.resource.introspection.OpaqueTokenIntrospector;
|
||||
import org.springframework.security.oauth2.server.resource.introspection.RestClientOpaqueTokenIntrospector;
|
||||
import org.springframework.web.client.RestClient;
|
||||
|
||||
@Configuration
|
||||
public class RestClientOpaqueTokenIntrospectorConfiguration {
|
||||
|
||||
// tag::restclient-simple[]
|
||||
@Bean
|
||||
public OpaqueTokenIntrospector introspector(String introspectionUri, String clientId, String clientSecret) {
|
||||
return RestClientOpaqueTokenIntrospector.withIntrospectionUri(introspectionUri)
|
||||
.clientId(clientId)
|
||||
.clientSecret(clientSecret)
|
||||
.build();
|
||||
}
|
||||
// end::restclient-simple[]
|
||||
|
||||
// tag::restclient-timeouts[]
|
||||
@Bean
|
||||
public OpaqueTokenIntrospector introspectorWithTimeouts(String introspectionUri, String clientId,
|
||||
String clientSecret) {
|
||||
SimpleClientHttpRequestFactory requestFactory = new SimpleClientHttpRequestFactory();
|
||||
requestFactory.setConnectTimeout(Duration.ofSeconds(60));
|
||||
requestFactory.setReadTimeout(Duration.ofSeconds(60));
|
||||
RestClient restClient = RestClient.builder()
|
||||
.requestFactory(requestFactory)
|
||||
.defaultHeaders((headers) -> headers.setBasicAuth(clientId, clientSecret))
|
||||
.build();
|
||||
return new RestClientOpaqueTokenIntrospector(introspectionUri, restClient);
|
||||
}
|
||||
// end::restclient-timeouts[]
|
||||
|
||||
}
|
||||
@ -0,0 +1,122 @@
|
||||
/*
|
||||
* Copyright 2004-present 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.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.security.docs.servlet.oauth2.resourceserver.opaquetokentimeoutsrestclient;
|
||||
|
||||
import java.time.Duration;
|
||||
import java.time.Instant;
|
||||
import java.util.Arrays;
|
||||
import java.util.Base64;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
|
||||
import okhttp3.mockwebserver.Dispatcher;
|
||||
import okhttp3.mockwebserver.MockResponse;
|
||||
import okhttp3.mockwebserver.MockWebServer;
|
||||
import okhttp3.mockwebserver.RecordedRequest;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import org.springframework.http.HttpHeaders;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.http.client.SimpleClientHttpRequestFactory;
|
||||
import org.springframework.security.oauth2.core.OAuth2AuthenticatedPrincipal;
|
||||
import org.springframework.security.oauth2.core.OAuth2TokenIntrospectionClaimNames;
|
||||
import org.springframework.security.oauth2.server.resource.introspection.OpaqueTokenIntrospector;
|
||||
import org.springframework.security.oauth2.server.resource.introspection.RestClientOpaqueTokenIntrospector;
|
||||
import org.springframework.web.client.RestClient;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
/**
|
||||
* Tests for {@link RestClientOpaqueTokenIntrospectorConfiguration} sample snippets.
|
||||
*/
|
||||
class RestClientOpaqueTokenIntrospectorConfigurationTests {
|
||||
|
||||
private static final String CLIENT_ID = "client";
|
||||
|
||||
private static final String CLIENT_SECRET = "secret";
|
||||
|
||||
private static final String ACTIVE_RESPONSE = """
|
||||
{
|
||||
"active": true,
|
||||
"sub": "Z5O3upPC88QrAjx00dis",
|
||||
"scope": "read write",
|
||||
"exp": 1419356238,
|
||||
"iat": 1419350238
|
||||
}
|
||||
""";
|
||||
|
||||
@Test
|
||||
void introspectorWhenBuilderThenIntrospectsSuccessfully() throws Exception {
|
||||
try (MockWebServer server = new MockWebServer()) {
|
||||
server.setDispatcher(requiresAuth(CLIENT_ID, CLIENT_SECRET, ACTIVE_RESPONSE));
|
||||
String introspectionUri = server.url("/introspect").toString();
|
||||
OpaqueTokenIntrospector introspector = RestClientOpaqueTokenIntrospector
|
||||
.withIntrospectionUri(introspectionUri)
|
||||
.clientId(CLIENT_ID)
|
||||
.clientSecret(CLIENT_SECRET)
|
||||
.build();
|
||||
OAuth2AuthenticatedPrincipal principal = introspector.introspect("token");
|
||||
assertThat(principal.getAttributes()).isNotNull()
|
||||
.containsEntry(OAuth2TokenIntrospectionClaimNames.ACTIVE, true)
|
||||
.containsEntry(OAuth2TokenIntrospectionClaimNames.SUB, "Z5O3upPC88QrAjx00dis")
|
||||
.containsEntry(OAuth2TokenIntrospectionClaimNames.EXP, Instant.ofEpochSecond(1419356238));
|
||||
assertThat((List<String>) principal.getAttribute(OAuth2TokenIntrospectionClaimNames.SCOPE))
|
||||
.isEqualTo(Arrays.asList("read", "write"));
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
void introspectorWithTimeoutsWhenCustomRestClientThenIntrospectsSuccessfully() throws Exception {
|
||||
try (MockWebServer server = new MockWebServer()) {
|
||||
server.setDispatcher(requiresAuth(CLIENT_ID, CLIENT_SECRET, ACTIVE_RESPONSE));
|
||||
String introspectionUri = server.url("/introspect").toString();
|
||||
SimpleClientHttpRequestFactory requestFactory = new SimpleClientHttpRequestFactory();
|
||||
requestFactory.setConnectTimeout(Duration.ofSeconds(60));
|
||||
requestFactory.setReadTimeout(Duration.ofSeconds(60));
|
||||
RestClient restClient = RestClient.builder()
|
||||
.requestFactory(requestFactory)
|
||||
.defaultHeaders((headers) -> headers.setBasicAuth(CLIENT_ID, CLIENT_SECRET))
|
||||
.build();
|
||||
OpaqueTokenIntrospector introspector = new RestClientOpaqueTokenIntrospector(introspectionUri, restClient);
|
||||
OAuth2AuthenticatedPrincipal principal = introspector.introspect("token");
|
||||
assertThat(principal.getAttributes()).isNotNull()
|
||||
.containsEntry(OAuth2TokenIntrospectionClaimNames.ACTIVE, true)
|
||||
.containsEntry(OAuth2TokenIntrospectionClaimNames.SUB, "Z5O3upPC88QrAjx00dis");
|
||||
}
|
||||
}
|
||||
|
||||
private static Dispatcher requiresAuth(String username, String password, String response) {
|
||||
return new Dispatcher() {
|
||||
@Override
|
||||
public MockResponse dispatch(RecordedRequest request) {
|
||||
String authorization = request.getHeader(HttpHeaders.AUTHORIZATION);
|
||||
return Optional.ofNullable(authorization)
|
||||
.filter((a) -> isAuthorized(authorization, username, password))
|
||||
.map((a) -> new MockResponse().setBody(response)
|
||||
.setHeader(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE))
|
||||
.orElse(new MockResponse().setResponseCode(401));
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
private static boolean isAuthorized(String authorization, String username, String password) {
|
||||
String decoded = new String(Base64.getDecoder().decode(authorization.substring(6)));
|
||||
String[] values = decoded.split(":", 2);
|
||||
return values.length == 2 && username.equals(values[0]) && password.equals(values[1]);
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,57 @@
|
||||
/*
|
||||
* Copyright 2004-present 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.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.security.kt.docs.servlet.oauth2.resourceserver.opaquetokentimeoutsrestclient
|
||||
|
||||
import org.springframework.context.annotation.Bean
|
||||
import org.springframework.context.annotation.Configuration
|
||||
import org.springframework.http.client.SimpleClientHttpRequestFactory
|
||||
import org.springframework.security.oauth2.server.resource.introspection.OpaqueTokenIntrospector
|
||||
import org.springframework.security.oauth2.server.resource.introspection.RestClientOpaqueTokenIntrospector
|
||||
import org.springframework.web.client.RestClient
|
||||
import java.time.Duration
|
||||
|
||||
@Configuration
|
||||
open class RestClientOpaqueTokenIntrospectorConfiguration {
|
||||
|
||||
// tag::restclient-simple[]
|
||||
@Bean
|
||||
open fun introspector(introspectionUri: String, clientId: String, clientSecret: String): OpaqueTokenIntrospector {
|
||||
return RestClientOpaqueTokenIntrospector.withIntrospectionUri(introspectionUri)
|
||||
.clientId(clientId)
|
||||
.clientSecret(clientSecret)
|
||||
.build()
|
||||
}
|
||||
// end::restclient-simple[]
|
||||
|
||||
// tag::restclient-timeouts[]
|
||||
@Bean
|
||||
open fun introspectorWithTimeouts(
|
||||
introspectionUri: String,
|
||||
clientId: String,
|
||||
clientSecret: String
|
||||
): OpaqueTokenIntrospector {
|
||||
val requestFactory = SimpleClientHttpRequestFactory()
|
||||
requestFactory.setConnectTimeout(Duration.ofSeconds(60))
|
||||
requestFactory.setReadTimeout(Duration.ofSeconds(60))
|
||||
val restClient = RestClient.builder()
|
||||
.requestFactory(requestFactory)
|
||||
.defaultHeaders { headers -> headers.setBasicAuth(clientId, clientSecret) }
|
||||
.build()
|
||||
return RestClientOpaqueTokenIntrospector(introspectionUri, restClient)
|
||||
}
|
||||
// end::restclient-timeouts[]
|
||||
}
|
||||
@ -0,0 +1,118 @@
|
||||
/*
|
||||
* Copyright 2004-present 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.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.security.kt.docs.servlet.oauth2.resourceserver.opaquetokentimeoutsrestclient
|
||||
|
||||
import okhttp3.mockwebserver.Dispatcher
|
||||
import okhttp3.mockwebserver.MockResponse
|
||||
import okhttp3.mockwebserver.MockWebServer
|
||||
import okhttp3.mockwebserver.RecordedRequest
|
||||
import org.junit.jupiter.api.Test
|
||||
import org.springframework.http.HttpHeaders
|
||||
import org.springframework.http.MediaType
|
||||
import org.springframework.http.client.SimpleClientHttpRequestFactory
|
||||
import org.springframework.security.oauth2.core.OAuth2AuthenticatedPrincipal
|
||||
import org.springframework.security.oauth2.core.OAuth2TokenIntrospectionClaimNames
|
||||
import org.springframework.security.oauth2.server.resource.introspection.OpaqueTokenIntrospector
|
||||
import org.springframework.security.oauth2.server.resource.introspection.RestClientOpaqueTokenIntrospector
|
||||
import org.springframework.web.client.RestClient
|
||||
import org.assertj.core.api.Assertions.assertThat
|
||||
import java.time.Duration
|
||||
import java.time.Instant
|
||||
import java.util.Base64
|
||||
|
||||
/**
|
||||
* Tests for [RestClientOpaqueTokenIntrospectorConfiguration] sample snippets.
|
||||
*/
|
||||
class RestClientOpaqueTokenIntrospectorConfigurationTests {
|
||||
|
||||
companion object {
|
||||
private const val CLIENT_ID = "client"
|
||||
private const val CLIENT_SECRET = "secret"
|
||||
private const val ACTIVE_RESPONSE = """
|
||||
{
|
||||
"active": true,
|
||||
"sub": "Z5O3upPC88QrAjx00dis",
|
||||
"scope": "read write",
|
||||
"exp": 1419356238,
|
||||
"iat": 1419350238
|
||||
}
|
||||
"""
|
||||
}
|
||||
|
||||
@Test
|
||||
fun introspectorWhenBuilderThenIntrospectsSuccessfully() {
|
||||
MockWebServer().use { server ->
|
||||
server.dispatcher = requiresAuth(CLIENT_ID, CLIENT_SECRET, ACTIVE_RESPONSE)
|
||||
server.start()
|
||||
val introspectionUri = server.url("/introspect").toString()
|
||||
val introspector: OpaqueTokenIntrospector = RestClientOpaqueTokenIntrospector
|
||||
.withIntrospectionUri(introspectionUri)
|
||||
.clientId(CLIENT_ID)
|
||||
.clientSecret(CLIENT_SECRET)
|
||||
.build()
|
||||
val principal: OAuth2AuthenticatedPrincipal = introspector.introspect("token")
|
||||
assertThat(principal.attributes).isNotNull
|
||||
assertThat(principal.attributes).containsEntry(OAuth2TokenIntrospectionClaimNames.ACTIVE, true)
|
||||
assertThat(principal.attributes).containsEntry(OAuth2TokenIntrospectionClaimNames.SUB, "Z5O3upPC88QrAjx00dis")
|
||||
assertThat(principal.attributes).containsEntry(OAuth2TokenIntrospectionClaimNames.EXP, Instant.ofEpochSecond(1419356238))
|
||||
assertThat(principal.getAttribute<Any>(OAuth2TokenIntrospectionClaimNames.SCOPE))
|
||||
.isEqualTo(listOf("read", "write"))
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun introspectorWithTimeoutsWhenCustomRestClientThenIntrospectsSuccessfully() {
|
||||
MockWebServer().use { server ->
|
||||
server.dispatcher = requiresAuth(CLIENT_ID, CLIENT_SECRET, ACTIVE_RESPONSE)
|
||||
server.start()
|
||||
val introspectionUri = server.url("/introspect").toString()
|
||||
val requestFactory = SimpleClientHttpRequestFactory()
|
||||
requestFactory.setConnectTimeout(Duration.ofSeconds(60))
|
||||
requestFactory.setReadTimeout(Duration.ofSeconds(60))
|
||||
val restClient = RestClient.builder()
|
||||
.requestFactory(requestFactory)
|
||||
.defaultHeaders { headers -> headers.setBasicAuth(CLIENT_ID, CLIENT_SECRET) }
|
||||
.build()
|
||||
val introspector = RestClientOpaqueTokenIntrospector(introspectionUri, restClient)
|
||||
val principal: OAuth2AuthenticatedPrincipal = introspector.introspect("token")
|
||||
assertThat(principal.attributes).isNotNull
|
||||
assertThat(principal.attributes).containsEntry(OAuth2TokenIntrospectionClaimNames.ACTIVE, true)
|
||||
assertThat(principal.attributes).containsEntry(OAuth2TokenIntrospectionClaimNames.SUB, "Z5O3upPC88QrAjx00dis")
|
||||
}
|
||||
}
|
||||
|
||||
private fun requiresAuth(username: String, password: String, response: String): Dispatcher {
|
||||
return object : Dispatcher() {
|
||||
override fun dispatch(request: RecordedRequest): MockResponse {
|
||||
val authorization = request.getHeader(HttpHeaders.AUTHORIZATION)
|
||||
return if (authorization != null && isAuthorized(authorization, username, password)) {
|
||||
MockResponse()
|
||||
.setBody(response)
|
||||
.setHeader(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE)
|
||||
} else {
|
||||
MockResponse().setResponseCode(401)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun isAuthorized(authorization: String, username: String, password: String): Boolean {
|
||||
val decoded = String(Base64.getDecoder().decode(authorization.substring(6)))
|
||||
val values = decoded.split(":", limit = 2)
|
||||
return values.size == 2 && username == values[0] && password == values[1]
|
||||
}
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user