如何在 SystemTest 中使用 AuthorizationServer 来创建无需身份验证的 JWT 令牌
How to use AuthorizationServer in a SystemTest to create JWT tokens without Authentication
我有一个系统测试。这意味着,我启动所有应用程序并仅通过执行 REST 调用来访问它们。我还为每个测试创建一个新用户。
现在我必须为我的应用程序添加安全性。这将是“OpenId 连接”。目前没有任何实施。由于有很多教程,我认为实施起来会很“容易”。但是我不确定如何处理我的 SystemTest。
我认为一种解决方案是使用 https://github.com/spring-projects/spring-authorization-server/releases/tag/0.2.0. See also https://www.baeldung.com/spring-security-oauth-auth-server#authServerImplementation
我的资源服务器只有这个配置
spring:
security:
oauth2:
resourceserver:
jwt:
issuer-uri: http://auth-server:9000
我认为我的测试应该是这样的:
- 使用不安全的 Rest 调用创建用户(技术 API)。用户将被保存在数据库中
- 使用我从 1) 知道的用户详细信息调用授权服务器。这会给我一个 JWT 令牌。
- 像客户端一样调用 REST API。添加 Header JWT 令牌。
- 这种情况由 Spring 自动处理:资源服务器调用授权服务器获取证书(参见 issuer-uri)并验证 JWT。
问题:
- 你知道我的 SystemTest 的更好解决方案吗
- 你知道如何实现 2)
更新:另一个想法:
也许在 SystemTest 中使用一个 slim OpenId Connect Client 会很好。然后我只需要修改授权服务器来动态注册用户。我还必须确保用户不需要凭据,必须只允许他做事。
此致
G
我能够解决我的问题 :-) 我创建了一个包含此控制器和其他 类 的应用程序。
我希望它能帮助其他开发者:-)
import com.nimbusds.jose.JOSEException;
import com.nimbusds.jose.jwk.RSAKey;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import javax.annotation.PostConstruct;
import java.lang.invoke.MethodHandles;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.security.interfaces.RSAPrivateKey;
import java.security.interfaces.RSAPublicKey;
@RestController
@RequestMapping("/openid-connect/mock")
public class OpenIdConnectMockController {
static final Logger logger = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());
private KeyPair rsaKeyPair;
private RSAKey jwkRsaPublicKey;
@PostConstruct
public void generateKey() throws NoSuchAlgorithmException, JOSEException {
this.rsaKeyPair = generateRsaKeyPair(2048);
logger.info("generate key {}", this.rsaKeyPair.getPublic());
RSAPublicKey rsaPublicKey = (RSAPublicKey) this.rsaKeyPair.getPublic();
RSAPrivateKey rsaPrivateKey = (RSAPrivateKey) this.rsaKeyPair.getPrivate();
this.jwkRsaPublicKey = new RSAKey.Builder(rsaPublicKey).build();
logger.info("jwkRsaPublicKey (JWK-Format) {}", this.jwkRsaPublicKey);
}
@GetMapping(path = "/keys", produces = "application/json")
public String keys() {
logger.info("Keys was called {}", this.jwkRsaPublicKey.toString());
return "{\"keys\":[" + this.jwkRsaPublicKey.toString() + "]}";
}
@GetMapping(path = "/private-key", produces = "application/json")
public byte[] getPrivateKey() throws JOSEException {
RSAKey privateKey = new RSAKey.Builder((RSAPublicKey) this.rsaKeyPair.getPublic()).privateKey(this.rsaKeyPair.getPrivate()).build();
return privateKey.toRSAPrivateKey().getEncoded();
}
private KeyPair generateRsaKeyPair(int keyLengthInt) throws NoSuchAlgorithmException {
KeyPairGenerator keypairGenerator = KeyPairGenerator.getInstance("RSA");
keypairGenerator.initialize(keyLengthInt, new SecureRandom());
return keypairGenerator.generateKeyPair();
}
}
public static Jwt jwtTokenClient(String userId) {
byte[] privateKey = OpenIdConnectMockService.privateKey(openIdConnectMockWebClient);
return JwtUtil.createJWT(privateKey, UUID.randomUUID().toString(), "MS-SystemTest-Issuer", userId);
}
import io.jsonwebtoken.JwtBuilder;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import java.security.KeyFactory;
import java.security.NoSuchAlgorithmException;
import java.security.interfaces.RSAPrivateKey;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.PKCS8EncodedKeySpec;
import java.util.Date;
public class JwtUtil {
public static final long SECOND_IN_MILLIS = 1000;
public static final long MINUTE_IN_MILLIS = SECOND_IN_MILLIS * 60;
public static final long HOUR_IN_MILLIS = MINUTE_IN_MILLIS * 60;
public static final long DAY_IN_MILLIS = HOUR_IN_MILLIS * 24;
private JwtUtil() {
}
public static Jwt createJWT(byte[] privateKey, String id, String issuer, String subject) {
//The JWT signature algorithm we will be using to sign the token
SignatureAlgorithm signatureAlgorithm = SignatureAlgorithm.RS256;
long nowMillis = System.currentTimeMillis();
//We will sign our JWT with our ApiKey secret
PKCS8EncodedKeySpec spec = new PKCS8EncodedKeySpec(privateKey);
KeyFactory rsaFact = null;
try {
rsaFact = KeyFactory.getInstance("RSA");
RSAPrivateKey key = (RSAPrivateKey) rsaFact.generatePrivate(spec);
JwtBuilder builder = Jwts.builder().setId(id)
.setIssuedAt(new Date(nowMillis))
.setSubject(subject)
.setIssuer(issuer)
.setExpiration(new Date(nowMillis + DAY_IN_MILLIS))
.signWith(signatureAlgorithm, key);
//Builds the JWT and serializes it to a compact, URL-safe string
return new Jwt(builder.compact());
} catch (NoSuchAlgorithmException | InvalidKeySpecException e) {
throw new IllegalStateException(e);
}
}
}
我有一个系统测试。这意味着,我启动所有应用程序并仅通过执行 REST 调用来访问它们。我还为每个测试创建一个新用户。
现在我必须为我的应用程序添加安全性。这将是“OpenId 连接”。目前没有任何实施。由于有很多教程,我认为实施起来会很“容易”。但是我不确定如何处理我的 SystemTest。
我认为一种解决方案是使用 https://github.com/spring-projects/spring-authorization-server/releases/tag/0.2.0. See also https://www.baeldung.com/spring-security-oauth-auth-server#authServerImplementation
我的资源服务器只有这个配置
spring:
security:
oauth2:
resourceserver:
jwt:
issuer-uri: http://auth-server:9000
我认为我的测试应该是这样的:
- 使用不安全的 Rest 调用创建用户(技术 API)。用户将被保存在数据库中
- 使用我从 1) 知道的用户详细信息调用授权服务器。这会给我一个 JWT 令牌。
- 像客户端一样调用 REST API。添加 Header JWT 令牌。
- 这种情况由 Spring 自动处理:资源服务器调用授权服务器获取证书(参见 issuer-uri)并验证 JWT。
问题:
- 你知道我的 SystemTest 的更好解决方案吗
- 你知道如何实现 2)
更新:另一个想法: 也许在 SystemTest 中使用一个 slim OpenId Connect Client 会很好。然后我只需要修改授权服务器来动态注册用户。我还必须确保用户不需要凭据,必须只允许他做事。
此致 G
我能够解决我的问题 :-) 我创建了一个包含此控制器和其他 类 的应用程序。 我希望它能帮助其他开发者:-)
import com.nimbusds.jose.JOSEException;
import com.nimbusds.jose.jwk.RSAKey;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import javax.annotation.PostConstruct;
import java.lang.invoke.MethodHandles;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.security.interfaces.RSAPrivateKey;
import java.security.interfaces.RSAPublicKey;
@RestController
@RequestMapping("/openid-connect/mock")
public class OpenIdConnectMockController {
static final Logger logger = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());
private KeyPair rsaKeyPair;
private RSAKey jwkRsaPublicKey;
@PostConstruct
public void generateKey() throws NoSuchAlgorithmException, JOSEException {
this.rsaKeyPair = generateRsaKeyPair(2048);
logger.info("generate key {}", this.rsaKeyPair.getPublic());
RSAPublicKey rsaPublicKey = (RSAPublicKey) this.rsaKeyPair.getPublic();
RSAPrivateKey rsaPrivateKey = (RSAPrivateKey) this.rsaKeyPair.getPrivate();
this.jwkRsaPublicKey = new RSAKey.Builder(rsaPublicKey).build();
logger.info("jwkRsaPublicKey (JWK-Format) {}", this.jwkRsaPublicKey);
}
@GetMapping(path = "/keys", produces = "application/json")
public String keys() {
logger.info("Keys was called {}", this.jwkRsaPublicKey.toString());
return "{\"keys\":[" + this.jwkRsaPublicKey.toString() + "]}";
}
@GetMapping(path = "/private-key", produces = "application/json")
public byte[] getPrivateKey() throws JOSEException {
RSAKey privateKey = new RSAKey.Builder((RSAPublicKey) this.rsaKeyPair.getPublic()).privateKey(this.rsaKeyPair.getPrivate()).build();
return privateKey.toRSAPrivateKey().getEncoded();
}
private KeyPair generateRsaKeyPair(int keyLengthInt) throws NoSuchAlgorithmException {
KeyPairGenerator keypairGenerator = KeyPairGenerator.getInstance("RSA");
keypairGenerator.initialize(keyLengthInt, new SecureRandom());
return keypairGenerator.generateKeyPair();
}
}
public static Jwt jwtTokenClient(String userId) {
byte[] privateKey = OpenIdConnectMockService.privateKey(openIdConnectMockWebClient);
return JwtUtil.createJWT(privateKey, UUID.randomUUID().toString(), "MS-SystemTest-Issuer", userId);
}
import io.jsonwebtoken.JwtBuilder;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import java.security.KeyFactory;
import java.security.NoSuchAlgorithmException;
import java.security.interfaces.RSAPrivateKey;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.PKCS8EncodedKeySpec;
import java.util.Date;
public class JwtUtil {
public static final long SECOND_IN_MILLIS = 1000;
public static final long MINUTE_IN_MILLIS = SECOND_IN_MILLIS * 60;
public static final long HOUR_IN_MILLIS = MINUTE_IN_MILLIS * 60;
public static final long DAY_IN_MILLIS = HOUR_IN_MILLIS * 24;
private JwtUtil() {
}
public static Jwt createJWT(byte[] privateKey, String id, String issuer, String subject) {
//The JWT signature algorithm we will be using to sign the token
SignatureAlgorithm signatureAlgorithm = SignatureAlgorithm.RS256;
long nowMillis = System.currentTimeMillis();
//We will sign our JWT with our ApiKey secret
PKCS8EncodedKeySpec spec = new PKCS8EncodedKeySpec(privateKey);
KeyFactory rsaFact = null;
try {
rsaFact = KeyFactory.getInstance("RSA");
RSAPrivateKey key = (RSAPrivateKey) rsaFact.generatePrivate(spec);
JwtBuilder builder = Jwts.builder().setId(id)
.setIssuedAt(new Date(nowMillis))
.setSubject(subject)
.setIssuer(issuer)
.setExpiration(new Date(nowMillis + DAY_IN_MILLIS))
.signWith(signatureAlgorithm, key);
//Builds the JWT and serializes it to a compact, URL-safe string
return new Jwt(builder.compact());
} catch (NoSuchAlgorithmException | InvalidKeySpecException e) {
throw new IllegalStateException(e);
}
}
}