Move JWT system out of router & add possibilité to custom internal Authenticator
This commit is contained in:
parent
9193e0d9d3
commit
8a6b744519
5 changed files with 134 additions and 68 deletions
|
@ -2,7 +2,7 @@ package dev.peerat.framework;
|
||||||
|
|
||||||
import java.net.Socket;
|
import java.net.Socket;
|
||||||
|
|
||||||
import org.jose4j.jwt.consumer.InvalidJwtException;
|
import dev.peerat.framework.auth.AuthException;
|
||||||
|
|
||||||
public class Client<U extends User> extends Thread{
|
public class Client<U extends User> extends Thread{
|
||||||
|
|
||||||
|
@ -28,7 +28,7 @@ public class Client<U extends User> extends Thread{
|
||||||
router.exec(context, reader, writer);
|
router.exec(context, reader, writer);
|
||||||
writer.flush();
|
writer.flush();
|
||||||
writer.close();
|
writer.close();
|
||||||
}catch(InvalidJwtException e){
|
}catch(AuthException e){
|
||||||
this.router.getExceptionLogger().setValue(e);
|
this.router.getExceptionLogger().setValue(e);
|
||||||
}catch(Throwable e){
|
}catch(Throwable e){
|
||||||
this.router.getExceptionLogger().setValue(e);
|
this.router.getExceptionLogger().setValue(e);
|
||||||
|
@ -45,13 +45,13 @@ public class Client<U extends User> extends Thread{
|
||||||
if(context != null) router.getLogger().setValue(context);
|
if(context != null) router.getLogger().setValue(context);
|
||||||
}
|
}
|
||||||
|
|
||||||
private User isLogin(RequestType type, HttpReader reader) throws InvalidJwtException{
|
private User isLogin(RequestType type, HttpReader reader) throws AuthException{
|
||||||
String auth = reader.getHeader("Authorization");
|
String auth = reader.getHeader("Authorization");
|
||||||
if(auth == null) return null;
|
if(auth == null) return null;
|
||||||
auth = auth.substring(7);
|
auth = auth.substring(7);
|
||||||
try{
|
try{
|
||||||
return this.router.getUser(auth);
|
return this.router.getUser(auth);
|
||||||
}catch(InvalidJwtException e){
|
}catch(Exception e){
|
||||||
try{
|
try{
|
||||||
writer.response(401, this.router.getDefaultHeaders(type));
|
writer.response(401, this.router.getDefaultHeaders(type));
|
||||||
writer.flush();
|
writer.flush();
|
||||||
|
@ -59,7 +59,7 @@ public class Client<U extends User> extends Thread{
|
||||||
}catch(Exception ex){
|
}catch(Exception ex){
|
||||||
this.router.getExceptionLogger().setValue(ex);
|
this.router.getExceptionLogger().setValue(ex);
|
||||||
}
|
}
|
||||||
throw e;
|
throw new AuthException(e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -7,27 +7,13 @@ import java.lang.reflect.Constructor;
|
||||||
import java.lang.reflect.Method;
|
import java.lang.reflect.Method;
|
||||||
import java.net.ServerSocket;
|
import java.net.ServerSocket;
|
||||||
import java.net.Socket;
|
import java.net.Socket;
|
||||||
import java.security.Key;
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
|
||||||
import java.util.function.Consumer;
|
|
||||||
import java.util.function.Function;
|
|
||||||
|
|
||||||
import javax.net.ssl.SSLServerSocket;
|
import javax.net.ssl.SSLServerSocket;
|
||||||
import javax.net.ssl.SSLServerSocketFactory;
|
import javax.net.ssl.SSLServerSocketFactory;
|
||||||
|
|
||||||
import org.jose4j.jwa.AlgorithmConstraints.ConstraintType;
|
import dev.peerat.framework.auth.Authenticator;
|
||||||
import org.jose4j.jwk.JsonWebKey.OutputControlLevel;
|
|
||||||
import org.jose4j.jwk.RsaJsonWebKey;
|
|
||||||
import org.jose4j.jwk.RsaJwkGenerator;
|
|
||||||
import org.jose4j.jws.AlgorithmIdentifiers;
|
|
||||||
import org.jose4j.jws.JsonWebSignature;
|
|
||||||
import org.jose4j.jwt.JwtClaims;
|
|
||||||
import org.jose4j.jwt.consumer.InvalidJwtException;
|
|
||||||
import org.jose4j.jwt.consumer.JwtConsumer;
|
|
||||||
import org.jose4j.jwt.consumer.JwtConsumerBuilder;
|
|
||||||
import org.jose4j.lang.JoseException;
|
|
||||||
|
|
||||||
public class Router<U extends User>{
|
public class Router<U extends User>{
|
||||||
|
|
||||||
|
@ -40,10 +26,7 @@ public class Router<U extends User>{
|
||||||
private RouteMapper<U>[] mappers;
|
private RouteMapper<U>[] mappers;
|
||||||
private List<RouteInterceptor> interceptors;
|
private List<RouteInterceptor> interceptors;
|
||||||
private Response noFileFound;
|
private Response noFileFound;
|
||||||
private RsaJsonWebKey rsaJsonWebKey;
|
private Authenticator<U> auth;
|
||||||
private JwtConsumer jwtConsumer;
|
|
||||||
private Consumer<JwtClaims> claims;
|
|
||||||
private Function<JwtClaims, U> userCreator;
|
|
||||||
private String[][] headers;
|
private String[][] headers;
|
||||||
private ServerSocket serverSocket;
|
private ServerSocket serverSocket;
|
||||||
|
|
||||||
|
@ -57,36 +40,11 @@ public class Router<U extends User>{
|
||||||
this.headers = new String[types][0];
|
this.headers = new String[types][0];
|
||||||
}
|
}
|
||||||
|
|
||||||
public Router<U> configureJwt(Consumer<JwtConsumerBuilder> consumer, Consumer<JwtClaims> claims, Function<JwtClaims, U> userCreator) throws Exception{
|
public Router<U> setAuthenticator(Authenticator<U> auth){
|
||||||
this.rsaJsonWebKey = RsaJwkGenerator.generateJwk(2048);
|
this.auth = auth;
|
||||||
configureJwtWithKey(consumer, claims, userCreator, this.rsaJsonWebKey.getKey());
|
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Router<U> configureJwt(Consumer<JwtConsumerBuilder> consumer, Consumer<JwtClaims> claims, Function<JwtClaims, U> userCreator, Map<String, Object> keyParams) throws Exception{
|
|
||||||
this.rsaJsonWebKey = new RsaJsonWebKey(keyParams);
|
|
||||||
configureJwtWithKey(consumer, claims, userCreator, this.rsaJsonWebKey.getKey());
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void configureJwtWithKey(Consumer<JwtConsumerBuilder> consumer, Consumer<JwtClaims> claims, Function<JwtClaims, U> userCreator, Key key) throws Exception{
|
|
||||||
JwtConsumerBuilder builder = new JwtConsumerBuilder()
|
|
||||||
.setRequireExpirationTime()
|
|
||||||
.setAllowedClockSkewInSeconds(30)
|
|
||||||
.setVerificationKey(key)
|
|
||||||
.setJwsAlgorithmConstraints(ConstraintType.PERMIT, AlgorithmIdentifiers.RSA_USING_SHA256);
|
|
||||||
|
|
||||||
consumer.accept(builder);
|
|
||||||
|
|
||||||
this.jwtConsumer = builder.build();
|
|
||||||
this.claims = claims;
|
|
||||||
this.userCreator = userCreator;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Map<String, Object> exportJwtKey(){
|
|
||||||
return this.rsaJsonWebKey.toParams(OutputControlLevel.INCLUDE_PRIVATE);
|
|
||||||
}
|
|
||||||
|
|
||||||
public Router<U> addDefaultHeaders(RequestType type, String... headers){
|
public Router<U> addDefaultHeaders(RequestType type, String... headers){
|
||||||
String[] origin = this.headers[type.ordinal()];
|
String[] origin = this.headers[type.ordinal()];
|
||||||
String[] copy = new String[origin.length+headers.length];
|
String[] copy = new String[origin.length+headers.length];
|
||||||
|
@ -188,6 +146,10 @@ public class Router<U extends User>{
|
||||||
return this.headers[type.ordinal()];
|
return this.headers[type.ordinal()];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Authenticator<U> getAuthenticator(){
|
||||||
|
return this.auth;
|
||||||
|
}
|
||||||
|
|
||||||
void exec(Context context, HttpReader reader, HttpWriter writer) throws Exception{
|
void exec(Context context, HttpReader reader, HttpWriter writer) throws Exception{
|
||||||
if(this.mappers[context.getType().ordinal()].exec(context, reader, writer, this.interceptors)) return;
|
if(this.mappers[context.getType().ordinal()].exec(context, reader, writer, this.interceptors)) return;
|
||||||
if(noFileFound != null) noFileFound.exec(null, context, reader, writer);
|
if(noFileFound != null) noFileFound.exec(null, context, reader, writer);
|
||||||
|
@ -199,25 +161,16 @@ public class Router<U extends User>{
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public U getUser(String token) throws InvalidJwtException{
|
public U getUser(String token) throws Exception{
|
||||||
return this.userCreator.apply(this.jwtConsumer.processToClaims(token));
|
return this.auth != null ? this.auth.getUser(token) : null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public String createAuthUser(U user) throws JoseException{
|
public String createAuthUser(U user) throws Exception{
|
||||||
JwtClaims claims = new JwtClaims();
|
return this.auth.createAuthUser(user);
|
||||||
claims.setGeneratedJwtId(); // a unique identifier for the token
|
}
|
||||||
claims.setIssuedAtToNow(); // when the token was issued/created (now)
|
|
||||||
claims.setNotBeforeMinutesInThePast(2); // time before which the token is not yet valid (2 minutes ago)
|
|
||||||
this.claims.accept(claims);
|
|
||||||
|
|
||||||
user.write(claims);
|
public User isLogin(RequestType type, HttpReader reader) throws Exception{
|
||||||
|
return this.auth.isLogin(type, reader);
|
||||||
JsonWebSignature jws = new JsonWebSignature();
|
|
||||||
jws.setPayload(claims.toJson());
|
|
||||||
jws.setKey(rsaJsonWebKey.getPrivateKey());
|
|
||||||
jws.setKeyIdHeaderValue(rsaJsonWebKey.getKeyId());
|
|
||||||
jws.setAlgorithmHeaderValue(AlgorithmIdentifiers.RSA_USING_SHA256);
|
|
||||||
return jws.getCompactSerialization();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public Locker<Context> getLogger(){
|
public Locker<Context> getLogger(){
|
||||||
|
|
17
src/dev/peerat/framework/auth/AuthException.java
Normal file
17
src/dev/peerat/framework/auth/AuthException.java
Normal file
|
@ -0,0 +1,17 @@
|
||||||
|
package dev.peerat.framework.auth;
|
||||||
|
|
||||||
|
public class AuthException extends Exception{
|
||||||
|
|
||||||
|
public AuthException(String message){
|
||||||
|
super(message);
|
||||||
|
}
|
||||||
|
|
||||||
|
public AuthException(Throwable throwable){
|
||||||
|
super(throwable);
|
||||||
|
}
|
||||||
|
|
||||||
|
public AuthException(String message, Throwable throwable){
|
||||||
|
super(message, throwable);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
15
src/dev/peerat/framework/auth/Authenticator.java
Normal file
15
src/dev/peerat/framework/auth/Authenticator.java
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
package dev.peerat.framework.auth;
|
||||||
|
|
||||||
|
import dev.peerat.framework.HttpReader;
|
||||||
|
import dev.peerat.framework.RequestType;
|
||||||
|
import dev.peerat.framework.User;
|
||||||
|
|
||||||
|
public interface Authenticator<U extends User>{
|
||||||
|
|
||||||
|
U getUser(String token) throws Exception;
|
||||||
|
|
||||||
|
String createAuthUser(U user) throws Exception;
|
||||||
|
|
||||||
|
User isLogin(RequestType type, HttpReader reader) throws Exception;
|
||||||
|
|
||||||
|
}
|
81
src/dev/peerat/framework/auth/JwtAuthenticator.java
Normal file
81
src/dev/peerat/framework/auth/JwtAuthenticator.java
Normal file
|
@ -0,0 +1,81 @@
|
||||||
|
package dev.peerat.framework.auth;
|
||||||
|
|
||||||
|
import java.security.Key;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.function.Consumer;
|
||||||
|
import java.util.function.Function;
|
||||||
|
|
||||||
|
import org.jose4j.jwa.AlgorithmConstraints.ConstraintType;
|
||||||
|
import org.jose4j.jwk.RsaJsonWebKey;
|
||||||
|
import org.jose4j.jwk.RsaJwkGenerator;
|
||||||
|
import org.jose4j.jwk.JsonWebKey.OutputControlLevel;
|
||||||
|
import org.jose4j.jws.AlgorithmIdentifiers;
|
||||||
|
import org.jose4j.jws.JsonWebSignature;
|
||||||
|
import org.jose4j.jwt.JwtClaims;
|
||||||
|
import org.jose4j.jwt.consumer.JwtConsumer;
|
||||||
|
import org.jose4j.jwt.consumer.JwtConsumerBuilder;
|
||||||
|
|
||||||
|
import dev.peerat.framework.User;
|
||||||
|
|
||||||
|
public class JwtAuthenticator<U extends User>{
|
||||||
|
|
||||||
|
private RsaJsonWebKey rsaJsonWebKey;
|
||||||
|
private JwtConsumer jwtConsumer;
|
||||||
|
private Consumer<JwtClaims> claims;
|
||||||
|
private Function<JwtClaims, U> userCreator;
|
||||||
|
|
||||||
|
public JwtAuthenticator(){}
|
||||||
|
|
||||||
|
public JwtAuthenticator<U> configure(Consumer<JwtConsumerBuilder> consumer, Consumer<JwtClaims> claims, Function<JwtClaims, U> userCreator) throws Exception{
|
||||||
|
this.rsaJsonWebKey = RsaJwkGenerator.generateJwk(2048);
|
||||||
|
configureWithKey(consumer, claims, userCreator, this.rsaJsonWebKey.getKey());
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public JwtAuthenticator<U> configure(Consumer<JwtConsumerBuilder> consumer, Consumer<JwtClaims> claims, Function<JwtClaims, U> userCreator, Map<String, Object> keyParams) throws Exception{
|
||||||
|
this.rsaJsonWebKey = new RsaJsonWebKey(keyParams);
|
||||||
|
configureWithKey(consumer, claims, userCreator, this.rsaJsonWebKey.getKey());
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
private JwtAuthenticator<U> configureWithKey(Consumer<JwtConsumerBuilder> consumer, Consumer<JwtClaims> claims, Function<JwtClaims, U> userCreator, Key key) throws Exception{
|
||||||
|
JwtConsumerBuilder builder = new JwtConsumerBuilder()
|
||||||
|
.setRequireExpirationTime()
|
||||||
|
.setAllowedClockSkewInSeconds(30)
|
||||||
|
.setVerificationKey(key)
|
||||||
|
.setJwsAlgorithmConstraints(ConstraintType.PERMIT, AlgorithmIdentifiers.RSA_USING_SHA256);
|
||||||
|
|
||||||
|
consumer.accept(builder);
|
||||||
|
|
||||||
|
this.jwtConsumer = builder.build();
|
||||||
|
this.claims = claims;
|
||||||
|
this.userCreator = userCreator;
|
||||||
|
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Map<String, Object> exportKey(){
|
||||||
|
return this.rsaJsonWebKey.toParams(OutputControlLevel.INCLUDE_PRIVATE);
|
||||||
|
}
|
||||||
|
|
||||||
|
public U getUser(String token) throws Exception{
|
||||||
|
return this.userCreator.apply(this.jwtConsumer.processToClaims(token));
|
||||||
|
}
|
||||||
|
|
||||||
|
public String createAuthUser(U user) throws Exception{
|
||||||
|
JwtClaims claims = new JwtClaims();
|
||||||
|
claims.setGeneratedJwtId(); // a unique identifier for the token
|
||||||
|
claims.setIssuedAtToNow(); // when the token was issued/created (now)
|
||||||
|
claims.setNotBeforeMinutesInThePast(2); // time before which the token is not yet valid (2 minutes ago)
|
||||||
|
this.claims.accept(claims);
|
||||||
|
|
||||||
|
user.write(claims);
|
||||||
|
|
||||||
|
JsonWebSignature jws = new JsonWebSignature();
|
||||||
|
jws.setPayload(claims.toJson());
|
||||||
|
jws.setKey(rsaJsonWebKey.getPrivateKey());
|
||||||
|
jws.setKeyIdHeaderValue(rsaJsonWebKey.getKeyId());
|
||||||
|
jws.setAlgorithmHeaderValue(AlgorithmIdentifiers.RSA_USING_SHA256);
|
||||||
|
return jws.getCompactSerialization();
|
||||||
|
}
|
||||||
|
}
|
Loading…
Add table
Reference in a new issue