Browse Source

Backend - AuthService OK

pull/1/head
slixe 3 years ago
parent
commit
46ba0aec7e
19 changed files with 363 additions and 40 deletions
  1. +0
    -1
      build.gradle
  2. +0
    -11
      config/routes.groovy
  3. +21
    -0
      dero-benchmark-vue/.gitignore
  4. +0
    -0
      dero-benchmark-vue/src/views/auth/Login.vue
  5. +0
    -0
      dero-benchmark-vue/src/views/auth/UBenchmarks.vue
  6. +8
    -1
      src/main/java/fr/slixe/benchmarks/App.java
  7. +9
    -2
      src/main/java/fr/slixe/benchmarks/Main.java
  8. +15
    -15
      src/main/java/fr/slixe/benchmarks/MyModule.java
  9. +30
    -0
      src/main/java/fr/slixe/benchmarks/User.java
  10. +24
    -0
      src/main/java/fr/slixe/benchmarks/http/AuthMiddleware.java
  11. +11
    -0
      src/main/java/fr/slixe/benchmarks/http/UnauthorizedOperationException.java
  12. +55
    -0
      src/main/java/fr/slixe/benchmarks/http/controller/AuthController.groovy
  13. +2
    -5
      src/main/java/fr/slixe/benchmarks/http/controller/MainController.groovy
  14. +40
    -0
      src/main/java/fr/slixe/benchmarks/serialization/UserAdapter.java
  15. +106
    -0
      src/main/java/fr/slixe/benchmarks/service/AuthService.java
  16. +10
    -2
      src/main/java/fr/slixe/benchmarks/service/BenchmarkService.java
  17. +1
    -2
      src/main/resources/config.default.json
  18. +8
    -1
      src/main/resources/config/app.config.groovy
  19. +23
    -0
      src/main/resources/config/routes.groovy

+ 0
- 1
build.gradle View File

@@ -24,7 +24,6 @@ dependencies {
'com.sparkjava:spark-core:2.8.0',
'net.sf.trove4j:trove4j:3.0.3',
'com.google.code.gson:gson:2.8.5',
//'com.google.guava:guava:27.0.1-jre',
'com.mashape.unirest:unirest-java:1.4.9',
'org.apache.commons:commons-lang3:3.8.1',
'org.apache.logging.log4j:log4j-core:2.10.0'


+ 0
- 11
config/routes.groovy View File

@@ -1,11 +0,0 @@
package config;
group '/api', {
get '/benchmarks'
get '/unconfirmedBenchmarks'
post '/submit'
post '/confirm'
post '/delete'
}, [
action: 'main'
]

+ 21
- 0
dero-benchmark-vue/.gitignore View File

@@ -0,0 +1,21 @@
.DS_Store
node_modules
/dist

# local env files
.env.local
.env.*.local

# Log files
npm-debug.log*
yarn-debug.log*
yarn-error.log*

# Editor directories and files
.idea
.vscode
*.suo
*.ntvs*
*.njsproj
*.sln
*.sw?

+ 0
- 0
dero-benchmark-vue/src/views/auth/Login.vue View File


+ 0
- 0
dero-benchmark-vue/src/views/auth/UBenchmarks.vue View File


+ 8
- 1
src/main/java/fr/slixe/benchmarks/App.java View File

@@ -8,6 +8,7 @@ import com.google.inject.Inject;
import fr.litarvan.paladin.OnStart;
import fr.litarvan.paladin.OnStop;
import fr.litarvan.paladin.PaladinApp;
import fr.slixe.benchmarks.service.AuthService;
import fr.slixe.benchmarks.service.BenchmarkService;
import spark.Spark;
@@ -21,11 +22,17 @@ public class App
@Inject
private BenchmarkService benchmarkService;
@Inject
private AuthService authService;
@OnStart
public void start()
{
log.info("Loading benchmarks...");
benchmarkService.loadBenchmarks();
log.info("Loading admins...");
authService.loadUsers();
}
@OnStop
@@ -33,7 +40,7 @@ public class App
{
log.info("Shutting down http service...");
Spark.stop();
log.info("Saving benchmarks...");
benchmarkService.saveBenchmarks();


+ 9
- 2
src/main/java/fr/slixe/benchmarks/Main.java View File

@@ -6,13 +6,20 @@ import fr.slixe.benchmarks.http.SparkHttpServer;
public class Main
{
private static Paladin paladin;
public static void main(String[] args)
{
Paladin paladin = PaladinBuilder.create(App.class)
paladin = PaladinBuilder.create(App.class)
.addModule(new MyModule())
.loadCommandLineArguments(args)
.build();
paladin.start(new SparkHttpServer(paladin, paladin.getConfig().get("port", int.class)));
}
public static Paladin getPaladin()
{
return paladin;
}
}

+ 15
- 15
src/main/java/fr/slixe/benchmarks/MyModule.java View File

@@ -7,25 +7,25 @@ import com.google.gson.GsonBuilder;
import com.google.inject.AbstractModule;
import fr.slixe.benchmarks.serialization.BenchmarkAdapter;
import fr.slixe.benchmarks.serialization.UserAdapter;
public class MyModule extends AbstractModule {
public class MyModule extends AbstractModule
{
@Override
protected void configure()
{
bind(Gson.class).toInstance(new GsonBuilder().registerTypeAdapter(Benchmark.class, new BenchmarkAdapter()).setPrettyPrinting().addSerializationExclusionStrategy(new ExclusionStrategy()
{
@Override
public boolean shouldSkipField(FieldAttributes f)
{
return f.getAnnotation(JsonIgnore.class) != null;
}
bind(Gson.class).toInstance(new GsonBuilder().registerTypeAdapter(Benchmark.class, new BenchmarkAdapter())
.registerTypeAdapter(User.class, new UserAdapter()).setPrettyPrinting()
.addSerializationExclusionStrategy(new ExclusionStrategy() {
@Override
public boolean shouldSkipField(FieldAttributes f) {
return f.getAnnotation(JsonIgnore.class) != null;
}
@Override
public boolean shouldSkipClass(Class<?> clazz)
{
return false;
}
}).create());
@Override
public boolean shouldSkipClass(Class<?> clazz) {
return false;
}
}).create());
}
}

+ 30
- 0
src/main/java/fr/slixe/benchmarks/User.java View File

@@ -0,0 +1,30 @@
package fr.slixe.benchmarks;

public class User {

private final String username;
private final String hashedPassword;
private final String salt;

public User(String username, String hashedPassword, String salt)
{
this.username = username;
this.hashedPassword = hashedPassword;
this.salt = salt;
}
public String getUsername()
{
return this.username;
}
public String getHashedPassword()
{
return this.hashedPassword;
}
public String getSalt()
{
return this.salt;
}
}

+ 24
- 0
src/main/java/fr/slixe/benchmarks/http/AuthMiddleware.java View File

@@ -0,0 +1,24 @@
package fr.slixe.benchmarks.http;

import fr.litarvan.paladin.AfterEvent;
import fr.litarvan.paladin.BeforeEvent;
import fr.litarvan.paladin.http.Middleware;
import fr.litarvan.paladin.http.Request;
import fr.litarvan.paladin.http.Response;
import fr.litarvan.paladin.http.routing.RequestException;
import fr.litarvan.paladin.http.routing.Route;
import fr.slixe.benchmarks.User;

public class AuthMiddleware extends Middleware
{
@Override
public void before(BeforeEvent event, Request request, Response response, Route route) throws RequestException
{
if (request.getSession().get(User.class) == null) {
throw new UnauthorizedOperationException();
}
}

@Override
public void after(AfterEvent event, Request request, Response response, Route route) throws RequestException {}
}

+ 11
- 0
src/main/java/fr/slixe/benchmarks/http/UnauthorizedOperationException.java View File

@@ -0,0 +1,11 @@
package fr.slixe.benchmarks.http;

import fr.litarvan.paladin.http.routing.RequestException;

public class UnauthorizedOperationException extends RequestException
{
public UnauthorizedOperationException()
{
super("You don't have the rights to do that");
}
}

+ 55
- 0
src/main/java/fr/slixe/benchmarks/http/controller/AuthController.groovy View File

@@ -0,0 +1,55 @@
package fr.slixe.benchmarks.http.controller;

import org.slf4j.Logger
import org.slf4j.LoggerFactory

import com.google.inject.Inject

import fr.litarvan.paladin.Session
import fr.litarvan.paladin.http.Controller
import fr.litarvan.paladin.http.routing.RequestParams
import fr.slixe.benchmarks.User
import fr.slixe.benchmarks.http.InvalidParameterException
import fr.slixe.benchmarks.service.AuthService

public class AuthController extends Controller {

private static final Logger log = LoggerFactory.getLogger("DERO HTTP Auth Controller")

@Inject
private AuthService authService

@RequestParams(required = ["username", "password"])
def login(String username, String password, Session session)
{
if (password.length() > 64) {
throw new InvalidParameterException("Password is too long")
}
User user = authService.loginUsername(username, password)

if (user == null) {
throw new InvalidParameterException("Username or password is incorrect")
}

log.info(String.format("User %s is now logged in from %s.", user.getUsername()))

session[User] = user

[
token: session.token
]
}

def validate(Session session)
{
[
logged: session[User] != null
]
}

def logout(Session session)
{
session[User] = null
}
}

+ 2
- 5
src/main/java/fr/slixe/benchmarks/http/controller/MainController.groovy View File

@@ -1,12 +1,9 @@
package fr.slixe.benchmarks.http.controller;

import java.util.List;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.google.gson.Gson;
import com.google.gson.JsonObject;
import com.google.inject.Inject;

import fr.litarvan.paladin.http.Controller;
@@ -70,7 +67,7 @@ public class MainController extends Controller {
* @param int benchID
*/
@RequestParams(required = ["benchID"])
def confirm(int benchID) //TODO Add auth
def confirm(int benchID)
{
log.debug("Confirmation of Benchmark $benchID")
@@ -88,7 +85,7 @@ public class MainController extends Controller {
* @param int benchID
*/
@RequestParams(required = ["benchID"])
def delete(int benchID) //TODO Add auth
def delete(int benchID)
{
log.debug("Removing Benchmark $benchID")


+ 40
- 0
src/main/java/fr/slixe/benchmarks/serialization/UserAdapter.java View File

@@ -0,0 +1,40 @@
package fr.slixe.benchmarks.serialization;

import java.lang.reflect.Type;

import com.google.gson.JsonDeserializationContext;
import com.google.gson.JsonDeserializer;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.google.gson.JsonParseException;
import com.google.gson.JsonSerializationContext;
import com.google.gson.JsonSerializer;

import fr.slixe.benchmarks.User;

public class UserAdapter implements JsonSerializer<User>, JsonDeserializer<User> {

@Override
public User deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException
{
JsonObject jsonObject = json.getAsJsonObject();

String username = jsonObject.get("username").getAsString();
String hashedPassword = jsonObject.get("hashedPassword").getAsString();
String salt = jsonObject.get("salt").getAsString();

return new User(username, hashedPassword, salt);
}

@Override
public JsonElement serialize(User src, Type typeOfSrc, JsonSerializationContext context)
{
JsonObject json = new JsonObject();

json.addProperty("username", src.getUsername());
json.addProperty("hashedPassword", src.getHashedPassword());
json.addProperty("salt", src.getSalt());

return json;
}
}

+ 106
- 0
src/main/java/fr/slixe/benchmarks/service/AuthService.java View File

@@ -0,0 +1,106 @@
package fr.slixe.benchmarks.service;

import java.io.File;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.lang.reflect.Type;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.google.common.hash.Hashing;
import com.google.common.primitives.Bytes;
import com.google.gson.Gson;
import com.google.gson.reflect.TypeToken;
import com.google.gson.stream.JsonReader;
import com.google.inject.Inject;
import com.google.inject.Singleton;

import fr.slixe.benchmarks.User;

@Singleton
public class AuthService {
private static final Type USER_TYPE = new TypeToken<List<User>>(){}.getType();
private static final Logger log = LoggerFactory.getLogger("DERO Auth Service");
private final Map<String, User> users = new ConcurrentHashMap<>();
private final File file = new File("admins.json");
@Inject
private Gson gson;
public void loadUsers()
{
if (!this.file.exists())
try {
log.info("admins.json not found, creating it with default user.");

this.file.createNewFile();
createExampleUser();
} catch (IOException e) {
log.error(e.getMessage());
}
else
try {
JsonReader jsonReader = new JsonReader(new FileReader(file));
List<User> users = gson.fromJson(jsonReader, USER_TYPE);

for (User user : users)
{
this.users.put(user.getUsername(), user);
}

jsonReader.close();
} catch (IOException e) {
log.error(e.getMessage());
}
}
private void createExampleUser()
{
String username = "Slixe";
String password = "password123";
String salt = "salt123";

this.users.put(username, new User(username, AuthService.hash(password, salt), salt));
try (FileWriter fileWriter = new FileWriter(this.file)) {
gson.toJson(this.users.values(), USER_TYPE, fileWriter);
} catch (IOException e) {
log.error(e.getMessage());
}
}

public User loginUsername(String username, String password)
{
return login(users.get(username), password);
}

public User login(User user, String password)
{
if (user == null) {
return null;
}

String hash = AuthService.hash(password, user.getSalt());

if (!hash.equals(user.getHashedPassword()))
{
return null;
}

return user;
}
public static String hash(String password, String salt)
{
byte[] passwordSalted = Bytes.concat(salt.getBytes(), password.getBytes());
return Hashing.sha512().hashBytes(passwordSalted).toString();
}
}

+ 10
- 2
src/main/java/fr/slixe/benchmarks/service/BenchmarkService.java View File

@@ -78,7 +78,10 @@ public class BenchmarkService {
public boolean addUnconfirmedBenchmarks(Benchmark benchmark)
{
return this.unconfirmedBenchmarks.add(benchmark);
boolean result = this.unconfirmedBenchmarks.add(benchmark);
saveBenchmarks(this.unconfirmedBenchmarksFile, this.unconfirmedBenchmarks);

return result;
}

public boolean confirmBenchmark(int benchID)
@@ -89,6 +92,7 @@ public class BenchmarkService {
Benchmark benchmark = opt.get();
this.unconfirmedBenchmarks.remove(benchmark);
this.confirmedBenchmarks.add(benchmark);
saveBenchmarks();
}
return opt.isPresent();
@@ -102,9 +106,13 @@ public class BenchmarkService {
result = this.confirmedBenchmarks.removeIf(e -> e.getId() == benchID);
}

if (result) {
this.saveBenchmarks();
}

return result;
}
public int lastBenchId()
{
if (this.confirmedBenchmarks.size() == 0 && this.unconfirmedBenchmarks.size() == 0)


+ 1
- 2
src/main/resources/config.default.json View File

@@ -1,4 +1,3 @@
{
"port": 8080,
"password": "HelloWorld123"
"port": 8080
}

config/app.config.groovy → src/main/resources/config/app.config.groovy View File

@@ -3,6 +3,8 @@ package config;
import java.util.concurrent.TimeUnit
import fr.litarvan.paladin.http.AcceptCrossOriginRequestsMiddleware
import fr.slixe.benchmarks.http.AuthMiddleware
import fr.slixe.benchmarks.http.controller.AuthController
import fr.slixe.benchmarks.http.controller.MainController
[
@@ -12,9 +14,14 @@ import fr.slixe.benchmarks.http.controller.MainController
* The app controllers, call them whatever you want to
*/
controllers: [
main: MainController
main: MainController,
auth: AuthController
],
routeMiddlewares: [
auth: AuthMiddleware
],
/**
* Global middlewares (applied on all routes)
*/

+ 23
- 0
src/main/resources/config/routes.groovy View File

@@ -0,0 +1,23 @@
package config;
group '/api', {
get '/benchmarks', 'main:benchmarks'
group '', {
get '/unconfirmedBenchmarks'
post '/submit'
post '/confirm'
post '/delete'
}, [
action: 'main',
middleware: 'auth'
]
group '/auth', {
post '/validate'
post '/login'
post '/logout'
}, [
action: 'auth'
]
}

Loading…
Cancel
Save