From eccae6ead8f032926789ce4bac68a4782ee91b34 Mon Sep 17 00:00:00 2001 From: x7airworker Date: Sun, 23 Jan 2022 15:23:30 +0100 Subject: [PATCH 1/3] Added an auth system --- pom.xml | 6 ++ .../webutils/security/AbstractAuthSystem.java | 90 +++++++++++++++++++ .../webutils/security/AuthException.java | 7 ++ .../javawebstack/webutils/security/IUser.java | 14 +++ .../webutils/security/SimpleAuthSystem.java | 22 +++++ .../webutils/security/SimpleUser.java | 51 +++++++++++ 6 files changed, 190 insertions(+) create mode 100644 src/main/java/org/javawebstack/webutils/security/AbstractAuthSystem.java create mode 100644 src/main/java/org/javawebstack/webutils/security/AuthException.java create mode 100644 src/main/java/org/javawebstack/webutils/security/IUser.java create mode 100644 src/main/java/org/javawebstack/webutils/security/SimpleAuthSystem.java create mode 100644 src/main/java/org/javawebstack/webutils/security/SimpleUser.java diff --git a/pom.xml b/pom.xml index 0eb1b58..1104515 100644 --- a/pom.xml +++ b/pom.xml @@ -62,6 +62,12 @@ 5.8.1 test + + com.auth0 + java-jwt + 3.18.2 + true + diff --git a/src/main/java/org/javawebstack/webutils/security/AbstractAuthSystem.java b/src/main/java/org/javawebstack/webutils/security/AbstractAuthSystem.java new file mode 100644 index 0000000..e7e7799 --- /dev/null +++ b/src/main/java/org/javawebstack/webutils/security/AbstractAuthSystem.java @@ -0,0 +1,90 @@ +package org.javawebstack.webutils.security; + +import com.auth0.jwt.JWT; +import com.auth0.jwt.algorithms.Algorithm; +import com.auth0.jwt.interfaces.DecodedJWT; +import org.javawebstack.abstractdata.AbstractObject; +import org.javawebstack.httpserver.Exchange; + +import java.sql.Date; +import java.time.Instant; +import java.util.Optional; + +public abstract class AbstractAuthSystem { + private Algorithm algorithm; + private int tokenExpire = 3600; + + public AbstractAuthSystem(String secret) { + this(Algorithm.HMAC256(secret)); + } + + public AbstractAuthSystem(Algorithm algorithm) { + this.algorithm = algorithm; + } + + protected abstract Optional getUserByUsername(String username); + protected AbstractObject successMessage(String token) { + return new AbstractObject() + .set("success", true) + .set("token", token); + } + + public void setTokenExpire(int tokenExpire) { + this.tokenExpire = tokenExpire; + } + + public int getTokenExpire() { + return tokenExpire; + } + + public AbstractObject loginHandler(Exchange exchange) throws AuthException { + AbstractObject body = exchange.body(AbstractObject.class); + Optional oUser = getUserByUsername(body.string("username")); + if (!oUser.isPresent()) + throw new AuthException("Wrong credentials"); + IUser user = oUser.get(); + if (!user.checkPassword(body.string("password"))) + throw new AuthException("Wrong credentials"); + return successMessage(signToken(user)); + } + + public boolean tokenHandler (Exchange exchange) { + String bearer = exchange.bearerAuth(); + if (bearer != null) { + DecodedJWT jwt = JWT.require(algorithm).acceptExpiresAt(System.currentTimeMillis()).build().verify(bearer); + if (jwt != null) + exchange.attrib("jwt", jwt); + } + return false; + } + + public Object authHandler (Exchange exchange) throws AuthException { + if (exchange.attrib("jwt") == null) { + exchange.status(401); + throw new AuthException("Authentication required"); + } + return null; + } + + public IUser currentUser () { + Exchange exchange = Exchange.current(); + if (exchange == null) + throw new RuntimeException("Exchange not available in current Thread!"); + IUser user = exchange.attrib("user"); + if (user == null) { + DecodedJWT jwt = exchange.attrib("jwt"); + if (jwt == null) + throw new RuntimeException("JWT not found! Is the tokenHandler in place?"); + user = getUserByUsername(jwt.getSubject()).get(); + exchange.attrib("user", user); + } + return user; + } + + protected String signToken(IUser user) { + return JWT.create() + .withSubject(user.getUsername()) + .withExpiresAt(Date.from(Instant.now().plusSeconds(tokenExpire))) + .sign(algorithm); + } +} diff --git a/src/main/java/org/javawebstack/webutils/security/AuthException.java b/src/main/java/org/javawebstack/webutils/security/AuthException.java new file mode 100644 index 0000000..5ce5622 --- /dev/null +++ b/src/main/java/org/javawebstack/webutils/security/AuthException.java @@ -0,0 +1,7 @@ +package org.javawebstack.webutils.security; + +public class AuthException extends Exception { + public AuthException(String message) { + super(message); + } +} diff --git a/src/main/java/org/javawebstack/webutils/security/IUser.java b/src/main/java/org/javawebstack/webutils/security/IUser.java new file mode 100644 index 0000000..1452393 --- /dev/null +++ b/src/main/java/org/javawebstack/webutils/security/IUser.java @@ -0,0 +1,14 @@ +package org.javawebstack.webutils.security; + +import org.javawebstack.httpserver.Exchange; +import org.javawebstack.webutils.crypt.BCrypt; + +public interface IUser { + String getUsername(); + + String getPassword(); + + default boolean checkPassword (String password) { + return BCrypt.check(getPassword(), password); + } +} diff --git a/src/main/java/org/javawebstack/webutils/security/SimpleAuthSystem.java b/src/main/java/org/javawebstack/webutils/security/SimpleAuthSystem.java new file mode 100644 index 0000000..44f1650 --- /dev/null +++ b/src/main/java/org/javawebstack/webutils/security/SimpleAuthSystem.java @@ -0,0 +1,22 @@ +package org.javawebstack.webutils.security; + +import org.javawebstack.orm.ORM; +import org.javawebstack.orm.exception.ORMConfigurationException; +import org.javawebstack.orm.wrapper.SQL; + +import java.util.Optional; + +public class SimpleAuthSystem extends AbstractAuthSystem { + public SimpleAuthSystem(String secret, SQL sql) { + super(secret); + try { + ORM.register(SimpleUser.class, sql); + } catch (ORMConfigurationException e) { + e.printStackTrace(); + } + } + + protected Optional getUserByUsername(String username) { + return Optional.ofNullable(ORM.repo(SimpleUser.class).where("username", username).first()); + } +} diff --git a/src/main/java/org/javawebstack/webutils/security/SimpleUser.java b/src/main/java/org/javawebstack/webutils/security/SimpleUser.java new file mode 100644 index 0000000..70f9f6b --- /dev/null +++ b/src/main/java/org/javawebstack/webutils/security/SimpleUser.java @@ -0,0 +1,51 @@ +package org.javawebstack.webutils.security; + +import com.auth0.jwt.algorithms.Algorithm; +import org.javawebstack.orm.Model; +import org.javawebstack.orm.annotation.Column; +import org.javawebstack.orm.util.KeyType; + + +public class SimpleUser extends Model implements IUser { + + @Column(id = true, ai = true, key = KeyType.PRIMARY) + private long id; + @Column + private String username; + @Column + private String password; + + public SimpleUser() {} + + public SimpleUser(long id, String username, String password) { + this.id = id; + this.username = username; + this.password = password; + } + + public long getId() { + return id; + } + + public void setId(long id) { + this.id = id; + } + + @Override + public String getUsername() { + return username; + } + + public void setUsername(String username) { + this.username = username; + } + + @Override + public String getPassword() { + return password; + } + + public void setPassword(String password) { + this.password = password; + } +} From 7240ad92e2602adacfada815e6f9783b35b00c12 Mon Sep 17 00:00:00 2001 From: x7airworker Date: Sun, 23 Jan 2022 15:28:34 +0100 Subject: [PATCH 2/3] Changed name of authHandler to authMiddleware --- .../org/javawebstack/webutils/security/AbstractAuthSystem.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/org/javawebstack/webutils/security/AbstractAuthSystem.java b/src/main/java/org/javawebstack/webutils/security/AbstractAuthSystem.java index e7e7799..56e5f70 100644 --- a/src/main/java/org/javawebstack/webutils/security/AbstractAuthSystem.java +++ b/src/main/java/org/javawebstack/webutils/security/AbstractAuthSystem.java @@ -58,7 +58,7 @@ public boolean tokenHandler (Exchange exchange) { return false; } - public Object authHandler (Exchange exchange) throws AuthException { + public Object authMiddleware (Exchange exchange) throws AuthException { if (exchange.attrib("jwt") == null) { exchange.status(401); throw new AuthException("Authentication required"); From b38de837518c66f4ff88c41a23b02045320d9223 Mon Sep 17 00:00:00 2001 From: x7airworker Date: Sun, 23 Jan 2022 15:34:30 +0100 Subject: [PATCH 3/3] Change Annotation to be unchecked --- .../javawebstack/webutils/security/AbstractAuthSystem.java | 4 ++-- .../org/javawebstack/webutils/security/AuthException.java | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/main/java/org/javawebstack/webutils/security/AbstractAuthSystem.java b/src/main/java/org/javawebstack/webutils/security/AbstractAuthSystem.java index 56e5f70..f8bd09c 100644 --- a/src/main/java/org/javawebstack/webutils/security/AbstractAuthSystem.java +++ b/src/main/java/org/javawebstack/webutils/security/AbstractAuthSystem.java @@ -37,7 +37,7 @@ public int getTokenExpire() { return tokenExpire; } - public AbstractObject loginHandler(Exchange exchange) throws AuthException { + public AbstractObject loginHandler(Exchange exchange) { AbstractObject body = exchange.body(AbstractObject.class); Optional oUser = getUserByUsername(body.string("username")); if (!oUser.isPresent()) @@ -58,7 +58,7 @@ public boolean tokenHandler (Exchange exchange) { return false; } - public Object authMiddleware (Exchange exchange) throws AuthException { + public Object authMiddleware (Exchange exchange) { if (exchange.attrib("jwt") == null) { exchange.status(401); throw new AuthException("Authentication required"); diff --git a/src/main/java/org/javawebstack/webutils/security/AuthException.java b/src/main/java/org/javawebstack/webutils/security/AuthException.java index 5ce5622..6758b09 100644 --- a/src/main/java/org/javawebstack/webutils/security/AuthException.java +++ b/src/main/java/org/javawebstack/webutils/security/AuthException.java @@ -1,6 +1,6 @@ package org.javawebstack.webutils.security; -public class AuthException extends Exception { +public class AuthException extends RuntimeException { public AuthException(String message) { super(message); }