Move JWT system out of router & add possibilité to custom internal Authenticator

This commit is contained in:
jeffcheasey88 2024-10-14 16:10:45 +02:00
parent 9193e0d9d3
commit 8a6b744519
5 changed files with 134 additions and 68 deletions

View file

@ -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);
} }
} }
} }

View file

@ -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(){

View 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);
}
}

View 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;
}

View 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();
}
}