LoginExe extends Exelet { @Handler(auth = false, instances = VIEWER) public static MessageOrBuilder rq_login(ExeletContext context, RQ_Login rq) { log.debug("Processing login request from: {}", context.connector.getRemoteAddress()); var outcome = begin(); String username = rq.getUsername(); if (!ValidationUtil.username(username)) { log.debug("The username ({}) is invalid", username); return failure(outcome, INVALID_USERNAME); } User user = UserStore.getByUsername(username).orElse(null); if (user == null) { log.debug("The user ({}) does not exist", username); return failure(outcome, ACCESS_DENIED); } if (user.isExpired()) { log.debug("The user ({}) is expired", username); return failure(outcome, ACCESS_DENIED); } if (user.totpSecret().isPresent()) { var key = new SecretKeySpec(user.getTotpSecret(), TOTP.getAlgorithm()); try { if (rq.getTotp() != TOTP.generateOneTimePassword(key, Instant.now())) { log.debug("OTP validation failed", username); return failure(outcome, ACCESS_DENIED); } } catch (InvalidKeyException e) { log.error("Invalid TOTP secret", e); return failure(outcome, ACCESS_DENIED); } finally { try { key.destroy(); } catch (DestroyFailedException e) { log.error("Failed to destroy TOTP secret", e); return failure(outcome, ACCESS_DENIED); } } } if (!CryptoUtil.PBKDF2.check(rq.getPassword(), user.getHash())) { log.debug("Password validation failed", username); return failure(outcome, ACCESS_DENIED); } log.debug("Accepting login request for user: {}", username); context.connector.authenticate(); ProfileStore.getViewer(username).ifPresentOrElse(profile -> { profile.viewer().ip().set(context.connector.getRemoteAddress()); }, () -> { ProfileStore.create(profile -> { profile.uuid().set(context.connector.getRemoteUuid()); profile.instanceType().set(context.connector.getRemoteInstance()); profile.instanceFlavor().set(context.connector.getRemoteInstanceFlavor()); profile.viewer().username().set(username); profile.viewer().ip().set(context.connector.getRemoteAddress()); }); }); return success(outcome); } private  LoginExe(); @Handler(auth = true, instances = VIEWER) static void rq_logout(ExeletContext context, RQ_Logout rq); @Handler(auth = false, instances = VIEWER) static MessageOrBuilder rq_login(ExeletContext context, RQ_Login rq);  }
@Test @DisplayName("Login with an expired user fails") void rq_login_4() { UserStore.add(UserConfig.newBuilder().setUsername("user123").setPassword("pass123").setExpiration(123).build()); var rq = RQ_Login.newBuilder().setUsername("user123").setPassword("pass123").build(); var rs = LoginExe.rq_login(context, rq); assertFalse(((Outcome) rs).getResult()); }
@Test @DisplayName("Login with missing user fails") void rq_login_1() { var rq = RQ_Login.newBuilder().setUsername("user123").setPassword("pass123").build(); var rs = LoginExe.rq_login(context, rq); assertFalse(((Outcome) rs).getResult()); }
@Test @DisplayName("Login with incorrect password fails") void rq_login_2() { UserStore.add(UserConfig.newBuilder().setUsername("user123").setPassword("pass123").build()); var rq = RQ_Login.newBuilder().setUsername("user123").setPassword("pass1234").build(); var rs = LoginExe.rq_login(context, rq); assertFalse(((Outcome) rs).getResult()); }
@Test @DisplayName("Login with correct credentials succeeds") void rq_login_3() { UserStore.add(UserConfig.newBuilder().setUsername("user123").setPassword("pass123").build()); var rq = RQ_Login.newBuilder().setUsername("user123").setPassword("pass123").build(); var rs = LoginExe.rq_login(context, rq); assertTrue(((Outcome) rs).getResult()); }