暂存提交
This commit is contained in:
+42
@@ -0,0 +1,42 @@
|
||||
package com.baiyue.common.security;
|
||||
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import org.junit.jupiter.api.AfterEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.springframework.http.HttpHeaders;
|
||||
import org.springframework.mock.web.MockFilterChain;
|
||||
import org.springframework.mock.web.MockHttpServletRequest;
|
||||
import org.springframework.mock.web.MockHttpServletResponse;
|
||||
import org.springframework.security.core.context.SecurityContextHolder;
|
||||
import org.springframework.security.oauth2.jwt.Jwt;
|
||||
import org.springframework.security.oauth2.jwt.JwtDecoder;
|
||||
|
||||
import java.time.Instant;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
class JwtAuthenticationFilterTest {
|
||||
@AfterEach
|
||||
void clearContext() { SecurityContextHolder.clearContext(); }
|
||||
|
||||
@Test
|
||||
void authenticatesValidBearerDuringFilterChain() throws Exception {
|
||||
Jwt jwt = Jwt.withTokenValue("valid").header("alg", "none").subject("alice")
|
||||
.issuedAt(Instant.now()).expiresAt(Instant.now().plusSeconds(60))
|
||||
.claim("user_id", 1L).build();
|
||||
JwtDecoder decoder = token -> jwt;
|
||||
JwtAuthenticationFilter filter = new JwtAuthenticationFilter(decoder, new JwtClaimsMapper(),
|
||||
new JsonAuthenticationEntryPoint(new ObjectMapper()));
|
||||
MockHttpServletRequest request = new MockHttpServletRequest();
|
||||
request.addHeader(HttpHeaders.AUTHORIZATION, "Bearer valid");
|
||||
MockHttpServletResponse response = new MockHttpServletResponse();
|
||||
AtomicBoolean invoked = new AtomicBoolean();
|
||||
filter.doFilter(request, response, (request1, response1) -> {
|
||||
assertThat(SecurityContextHolder.getContext().getAuthentication()).isNotNull();
|
||||
invoked.set(true);
|
||||
});
|
||||
assertThat(invoked).isTrue();
|
||||
assertThat(SecurityContextHolder.getContext().getAuthentication()).isNull();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
package com.baiyue.common.security;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.springframework.security.oauth2.jwt.Jwt;
|
||||
|
||||
import java.time.Instant;
|
||||
import java.util.List;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
class JwtClaimsMapperTest {
|
||||
@Test
|
||||
void mapsTenantUserRolesAndPermissions() {
|
||||
Jwt jwt = Jwt.withTokenValue("token")
|
||||
.header("alg", "none")
|
||||
.subject("subject")
|
||||
.issuedAt(Instant.now())
|
||||
.expiresAt(Instant.now().plusSeconds(60))
|
||||
.claim("user_id", 42L)
|
||||
.claim("tenant_id", "7")
|
||||
.claim("username", "alice")
|
||||
.claim("app_code", "MERCHANT")
|
||||
.claim("client_type", "MERCHANT")
|
||||
.claim("permissions", List.of("order:read", "order:create"))
|
||||
.claim("roles", List.of("ADMIN"))
|
||||
.build();
|
||||
|
||||
BaiyueJwtAuthenticationToken authentication = new JwtClaimsMapper().map(jwt);
|
||||
assertThat(authentication.getPrincipal().userId()).isEqualTo(42L);
|
||||
assertThat(authentication.getPrincipal().tenantId()).isEqualTo(7L);
|
||||
assertThat(authentication.getAuthorities()).extracting("authority")
|
||||
.contains("order:read", "order:create", "ROLE_ADMIN", "APP_MERCHANT");
|
||||
}
|
||||
|
||||
@Test
|
||||
void fallsBackToNumericSubjectForUserId() {
|
||||
Jwt jwt = Jwt.withTokenValue("token")
|
||||
.header("alg", "none")
|
||||
.subject("99")
|
||||
.issuedAt(Instant.now())
|
||||
.expiresAt(Instant.now().plusSeconds(60))
|
||||
.claim("tenant_id", 0L)
|
||||
.claim("app_code", "PLATFORM")
|
||||
.build();
|
||||
|
||||
BaiyueJwtAuthenticationToken authentication = new JwtClaimsMapper().map(jwt);
|
||||
assertThat(authentication.getPrincipal().userId()).isEqualTo(99L);
|
||||
assertThat(authentication.getAuthorities()).extracting("authority").contains("APP_PLATFORM");
|
||||
}
|
||||
}
|
||||
+53
@@ -0,0 +1,53 @@
|
||||
package com.baiyue.common.security;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.springframework.data.redis.RedisConnectionFailureException;
|
||||
import org.springframework.data.redis.core.StringRedisTemplate;
|
||||
import org.springframework.security.oauth2.jwt.Jwt;
|
||||
|
||||
import java.time.Instant;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThatCode;
|
||||
import static org.assertj.core.api.Assertions.assertThatThrownBy;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
class RedisAccessTokenSessionValidatorTest {
|
||||
@Test
|
||||
void acceptsActiveSession() {
|
||||
StringRedisTemplate redis = mock(StringRedisTemplate.class);
|
||||
when(redis.hasKey("baiyue:auth:access:jti-1")).thenReturn(true);
|
||||
|
||||
assertThatCode(() -> new RedisAccessTokenSessionValidator(redis, "baiyue:auth")
|
||||
.validate(jwt("jti-1"))).doesNotThrowAnyException();
|
||||
}
|
||||
|
||||
@Test
|
||||
void rejectsRevokedSession() {
|
||||
StringRedisTemplate redis = mock(StringRedisTemplate.class);
|
||||
when(redis.hasKey("baiyue:auth:access:jti-1")).thenReturn(false);
|
||||
|
||||
assertThatThrownBy(() -> new RedisAccessTokenSessionValidator(redis, "baiyue:auth")
|
||||
.validate(jwt("jti-1")))
|
||||
.isInstanceOf(IllegalArgumentException.class)
|
||||
.hasMessageContaining("revoked or expired");
|
||||
}
|
||||
|
||||
@Test
|
||||
void failsClosedWhenRedisIsUnavailable() {
|
||||
StringRedisTemplate redis = mock(StringRedisTemplate.class);
|
||||
when(redis.hasKey("baiyue:auth:access:jti-1"))
|
||||
.thenThrow(new RedisConnectionFailureException("offline"));
|
||||
|
||||
assertThatThrownBy(() -> new RedisAccessTokenSessionValidator(redis, "baiyue:auth")
|
||||
.validate(jwt("jti-1")))
|
||||
.isInstanceOf(IllegalArgumentException.class)
|
||||
.hasMessageContaining("unavailable");
|
||||
}
|
||||
|
||||
private Jwt jwt(String jwtId) {
|
||||
return Jwt.withTokenValue("token").header("alg", "none")
|
||||
.subject("1").claim("jti", jwtId).issuedAt(Instant.now())
|
||||
.expiresAt(Instant.now().plusSeconds(60)).build();
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user