<version>2.8.3</version>
</dependency>
+ <dependency>
+ <groupId>org.rendersnake</groupId>
+ <artifactId>rendersnake</artifactId>
+ <version>1.9.0</version>
+ </dependency>
+
<!-- Loading data base in run time -->
<dependency>
<groupId>org.liquibase</groupId>
public class DataBaseAccessImpl implements DataBaseAccess {
private static final Logger LOGGER = LoggerFactory.getLogger(DataBaseAccessImpl.class);
+ private final DataSource dataSource;
+
+ public DataBaseAccessImpl(DataSource dataSource) {
+ this.dataSource = dataSource;
+ }
+
@Override
public List<Map<String, String>> executeQuery(
String query, ExecuteResultSet<ResultSet> executeResultSet, FillPreparedStatement fillStatement) {
protected List<Map<String, String>> executeQueryThrowable(
String query, ExecuteResultSet<ResultSet> executeResultSet, FillPreparedStatement fillStatement) throws SQLException {
- final DataSource dataSource = DoDataSourceContext.getInstance().getDataSource();
try {
- final Connection connection = dataSource.getConnection();
+ final Connection connection = this.dataSource.getConnection();
return this.doExecuteQuery(
query,
private static final String SURNAME = "SURNAME";
private static final String PASSWORD = "PASSWORD";
private static final String APP_ROLE_CODE = "APPLICATION_ROLE_CODE";
+
+ private final DataSource dataSource;
public CustomBasicAuthenticator(String context, DataSource dataSource) {
super(context);
+
+ this.dataSource = dataSource;
}
@Override
protected List<Map<String, String>> doQuery(String username, String password) {
- final DataBaseAccess dataBaseAccess = new DataBaseAccessImpl();
+ final DataBaseAccess dataBaseAccess = new DataBaseAccessImpl(this.dataSource);
return dataBaseAccess.executeQuery("SELECT * FROM ACCOUNT WHERE CODE = ? AND PASSWORD = ?",
answer ->
{
package com.prueba.core.context.security.handle;
import java.io.IOException;
-import java.net.URI;
-import java.time.LocalDateTime;
-import java.util.Map;
-import java.util.UUID;
-import java.util.concurrent.ConcurrentHashMap;
-import com.prueba.core.context.security.persistence.SessionInfo;
+import com.prueba.resources.controllers.LoginController;
import com.sun.net.httpserver.Headers;
import com.sun.net.httpserver.HttpExchange;
import com.sun.net.httpserver.HttpHandler;
public class LoginHandler implements HttpHandler {
public static final String LOGIN_PAGE = "/app/login/login.html?serviceName=http://localhost:8080";
-
+
+ private final LoginController loginController = new LoginController();
+
@Override
public void handle(HttpExchange httpExchange) throws IOException {
final Headers headers = httpExchange.getRequestHeaders();
+ loginController.handle(httpExchange);
-
- httpExchange.sendResponseHeaders(200, 0);
httpExchange.close();
}
final Headers headers = httpExchange.getRequestHeaders();
final String cookieValue = headers.getFirst(COOKIE_HEADER);
- if (cookieValue != null) {
- final UUID uuid = UUID.fromString(cookieValue);
- final SessionInfo sessionInfo = sessions.get(uuid);
- if (sessionInfo != null) {
- LocalDateTime currentDateTime = LocalDateTime.now();
- if (sessionInfo.getLastSessionTime().plusMinutes(5).compareTo(currentDateTime) > 0) {
- // Call next handler
-
- final SessionInfo newSessionInfo = new SessionInfo(sessionInfo.getUsername(), LocalDateTime.now());
- sessions.put(uuid, newSessionInfo);
- } else {
- this.doRedirec(httpExchange);
- }
- } else {
- this.doRedirec(httpExchange);
- }
+ final SessionInfo sessionInfo = getSessionInfo(httpExchange);
+ if (this.isValidSession(httpExchange)) {
+ // Call next handler
+
+ this.refreshSession(sessionInfo.getUUID(), sessionInfo.getUsername());
} else {
- this.doRedirec(httpExchange);
+ this.doRedirect(httpExchange);
}
httpExchange.close();
}
- protected void doRedirec(HttpExchange httpExchange) throws IOException {
+ public boolean isValidSession(HttpExchange httpExchange) {
+ final SessionInfo sessionInfo = getSessionInfo(httpExchange);
+
+ boolean isValid = false;
+
+ if (sessionInfo != null) {
+ LocalDateTime currentDateTime = LocalDateTime.now();
+ if (sessionInfo.getLastSessionTime().plusMinutes(5).compareTo(currentDateTime) > 0) {
+ isValid = true;
+ } else {
+ sessions.remove(sessionInfo).getUUID();
+ }
+ }
+
+ return isValid;
+ }
+
+ public void refreshSession(UUID uuid, String username) {
+ final SessionInfo newSessionInfo =
+ new SessionInfo(uuid, username, LocalDateTime.now());
+ sessions.put(uuid, newSessionInfo);
+ }
+
+ public Map<UUID, SessionInfo> getSessions() {
+ return this.sessions;
+ }
+
+ public SessionInfo getSessionInfo(HttpExchange httpExchange) {
+ final Headers headers = httpExchange.getRequestHeaders();
+ final String cookieValue = headers.getFirst(COOKIE_HEADER);
+ SessionInfo sessionInfo = null;
+
+ if (cookieValue != null) {
+ final UUID uuid = UUID.fromString(cookieValue);
+ sessionInfo = sessions.get(uuid);
+ }
+
+ return sessionInfo;
+ }
+
+ protected void doRedirect(HttpExchange httpExchange) throws IOException {
URI requestURI = httpExchange.getRequestURI();
String requestURIString = requestURI.toString();
Headers responseHeaders = httpExchange.getResponseHeaders();
package com.prueba.core.context.security.persistence;
import java.time.LocalDateTime;
+import java.util.UUID;
public class SessionInfo {
+ private final UUID uuid;
private final String username;
private final LocalDateTime lastSessionTime;
- public SessionInfo(String username, LocalDateTime lastSessionTime) {
+ public SessionInfo(UUID uuid, String username, LocalDateTime lastSessionTime) {
+ this.uuid = uuid;
this.username = username;
this.lastSessionTime = lastSessionTime;
}
+ public UUID getUUID() {
+ return uuid;
+ }
+
public String getUsername() {
return username;
}
import com.prueba.core.context.integration.liquibase.impl.LiquibaseContext;
import com.prueba.core.context.security.handle.LoginHandler;
import com.prueba.core.context.security.handle.SessionHandler;
+import com.prueba.resources.controllers.LoginController;
import com.sun.net.httpserver.HttpHandler;
--- /dev/null
+package com.prueba.core.web.controller;
+
+import com.sun.net.httpserver.HttpHandler;
+
+public interface Controller extends HttpHandler {
+
+ public String getURI();
+}
--- /dev/null
+package com.prueba.persistence.dao;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import javax.sql.DataSource;
+
+import com.prueba.core.context.integration.database.impl.DataBaseAccessImpl;
+import com.prueba.core.context.web.application.ApplicationWebContext;
+
+public class LoginDao {
+ private static final String CODE = "CODE";
+ private static final String NAME = "NAME";
+ private static final String SURNAME = "SURNAME";
+ private static final String PASSWORD = "PASSWORD";
+ private static final String APP_ROLE_CODE = "APPLICATION_ROLE_CODE";
+
+ public List<Map<String, String>> findUserByCodeAndPassword(String username, String password) {
+ final DataSource dataSource = ApplicationWebContext.getInstance().getDataSource();
+ final DataBaseAccessImpl dataBaseAccess = new DataBaseAccessImpl(dataSource);
+
+ return dataBaseAccess.executeQuery("SELECT * FROM ACCOUNT WHERE CODE = ? AND PASSWORD = ?",
+ answer ->
+ {
+ final List<Map<String, String>> result = new ArrayList<>();
+ while (answer.next()) {
+ final Map<String, String> row = new HashMap<>();
+ row.put(CODE, answer.getString(CODE));
+ row.put(NAME, answer.getString(NAME));
+ row.put(SURNAME, answer.getString(SURNAME));
+ row.put(PASSWORD, answer.getString(PASSWORD));
+ row.put(APP_ROLE_CODE, answer.getString(APP_ROLE_CODE));
+ result.add(row);
+ }
+
+ return result;
+ },
+ preparedStatement -> {
+ preparedStatement.setString(1, username);
+ preparedStatement.setString(2, password);
+ });
+ }
+}
--- /dev/null
+package com.prueba.resources.controllers;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.net.URI;
+import java.nio.charset.Charset;
+import java.util.UUID;
+
+import com.prueba.core.context.security.handle.SessionHandler;
+import com.prueba.core.context.security.persistence.SessionInfo;
+import com.prueba.core.context.web.application.ApplicationWebContext;
+import com.prueba.core.web.controller.Controller;
+import com.prueba.services.impl.LoginServiceImpl;
+import com.prueba.view.login.LoginFormImpl;
+import com.sun.net.httpserver.Headers;
+import com.sun.net.httpserver.HttpExchange;
+
+public class LoginController implements Controller {
+ private static final String URI = "/login/login.html";
+
+ @Override
+ public void handle(HttpExchange httpExchange) throws IOException {
+ final SessionHandler handler = (SessionHandler) ApplicationWebContext.getInstance().getWebHandler();
+ final String requestMethod = httpExchange.getRequestMethod();
+
+ switch (requestMethod) {
+ case "GET":
+ this.processLogin(handler, httpExchange);
+ break;
+ case "POST":
+ this.processLoginPost(handler, httpExchange);
+ break;
+ default:
+ httpExchange.sendResponseHeaders(404, 0);
+ break;
+ }
+
+ }
+
+ protected void processLogin(SessionHandler handler, HttpExchange httpExchange) throws IOException {
+ final String requestedURI = httpExchange.getRequestURI().toString();
+ final SessionInfo sessionInfo = handler.getSessionInfo(httpExchange);
+ final LoginFormImpl loginForm = new LoginFormImpl();
+
+ String html;
+ if (handler.isValidSession(httpExchange)) {
+ html = loginForm.doNoRequiredLogin();
+ handler.refreshSession(sessionInfo.getUUID(), sessionInfo.getUsername());
+ } else {
+ html = loginForm.doRequiredLogin(requestedURI);
+ }
+
+ httpExchange.sendResponseHeaders(200, html.length());
+
+ try (final OutputStream os = httpExchange.getResponseBody()) {
+ os.write(html.getBytes());
+ }
+
+ }
+
+ private void processLoginPost(SessionHandler handler, HttpExchange httpExchange) throws IOException {
+ final SessionInfo sessionInfo = handler.getSessionInfo(httpExchange);
+
+ if (!handler.isValidSession(httpExchange)) {
+ String body = this.getBody(httpExchange);
+ String [] formData = body.split("&");
+ if (formData.length == 2) {
+ String username = formData[0].split("=")[1];
+ String password = formData[1].split("=")[1];
+
+ LoginServiceImpl loginService = new LoginServiceImpl();
+ if (loginService.isValidUser(username, password)) {
+ UUID uuid = UUID.randomUUID();
+ setCookieHeader(httpExchange, uuid.toString());
+ handler.refreshSession(uuid, username);
+ doRedirect(httpExchange);
+ } else {
+ httpExchange.sendResponseHeaders(401, 0);
+ }
+ }
+ } else {
+ handler.refreshSession(sessionInfo.getUUID(), sessionInfo.getUsername());
+ doRedirect(httpExchange);
+ }
+ }
+
+ private String getBody (HttpExchange httpExchange) throws IOException {
+ try(final InputStream inputStream = httpExchange.getRequestBody();
+ final ByteArrayOutputStream byteBuffer = new ByteArrayOutputStream()) {
+
+ final int bufferSize = 1024;
+ final byte[] buffer = new byte[bufferSize];
+
+ int len = 0;
+ while ((len = inputStream.read(buffer)) != -1) {
+ byteBuffer.write(buffer, 0, len);
+ }
+
+ return new String(byteBuffer.toByteArray(), Charset.forName("UTF-8"));
+ }
+ }
+
+ protected void setCookieHeader(HttpExchange httpExchange, String UUIDString) {
+ Headers headers = httpExchange.getResponseHeaders();
+ headers.remove("Set-Cookie");
+ headers.set("Set-Cookie", UUIDString + "; path=/");
+ }
+
+ protected void doRedirect(HttpExchange httpExchange) throws IOException {
+ URI requestURI = httpExchange.getRequestURI();
+ String requestURIString = requestURI.toString();
+ String[] urls = requestURIString.split("serviceName=");
+ if (urls.length == 2) {
+ String serviceName = urls[1];
+ Headers responseHeaders = httpExchange.getResponseHeaders();
+ responseHeaders.add("Location", serviceName);
+ httpExchange.sendResponseHeaders(302, 0);
+ }
+ }
+
+ @Override
+ public String getURI() {
+ return URI;
+ }
+
+}
--- /dev/null
+package com.prueba.services.impl;
+
+import com.prueba.persistence.dao.LoginDao;
+
+public class LoginServiceImpl {
+
+ public boolean isValidUser(String username, String password) {
+ final LoginDao dao = new LoginDao();
+
+ if (!dao.findUserByCodeAndPassword(username, password).isEmpty()) {
+ return true;
+ } else {
+ return false;
+ }
+
+ }
+}
--- /dev/null
+package com.prueba.view.login;
+
+import static org.rendersnake.HtmlAttributesFactory.for_;
+import static org.rendersnake.HtmlAttributesFactory.id;
+import static org.rendersnake.HtmlAttributesFactory.type;
+
+import java.io.IOException;
+
+import org.rendersnake.HtmlCanvas;
+
+public class LoginFormImpl {
+ private static final String ID_USERNAME = "username";
+ private static final String ID_PASSWORD = "password";
+ private static final String VAR_USERNAME = "username";
+ private static final String VAR_PASSWORD = "password";
+
+ public String doNoRequiredLogin() throws IOException {
+ final HtmlCanvas html = new HtmlCanvas();
+ return html
+ .html()
+ .body()
+ .h1().content("NO REQUIRED LOGIN")
+ ._body()
+ ._html()
+ .toHtml();
+ }
+
+ public String doRequiredLogin(String requestedURI) throws IOException {
+ final HtmlCanvas html = new HtmlCanvas();
+ return html
+ .html()
+ .form(id("sample").action(requestedURI).method("post"))
+ .label(for_(ID_USERNAME)).write("Username:")._label()
+ .input(
+ id(ID_USERNAME)
+ .name(VAR_USERNAME))
+ .br()
+ .label(for_(ID_PASSWORD)).write("Password:")._label()
+ .input(
+ type("password")
+ .id(ID_PASSWORD)
+ .name(VAR_PASSWORD))
+ .br()
+ .input(type("submit").value("Log me in"))
+ ._form()
+ .toHtml();
+ }
+}
private DataSource dataSource;
private LiquibaseContext liquibaseContext;
+ private DataBaseAccess dataBaseAccess;
@Before
public void init() {
dataSource = DoDataSourceContext.getInstance().getDataSource();
liquibaseContext = new LiquibaseContext(dataSource);
liquibaseContext.init();
+ dataBaseAccess = new DataBaseAccessImpl(dataSource);
}
@Test
public void whenLoadLiquibaseContextThenReturnResultsFromDatabase() {
- final DataBaseAccess dataBaseAccess = new DataBaseAccessImpl();
final List<Map<String, String>> dataResult = dataBaseAccess.executeQuery("SELECT * FROM ACCOUNT",
answer ->
{
@Test
public void whenLoadLiquibaseContextThenReturnResultsFromDatabaseUsingParameters() {
- final DataBaseAccess dataBaseAccess = new DataBaseAccessImpl();
final List<Map<String, String>> dataResult = dataBaseAccess.executeQuery("SELECT * FROM ACCOUNT WHERE CODE = ?",
answer ->
{
@Test
public void whenLoadLiquibaseContextAndNotUserFoundThenDoNotReturResultsFromDatabase() {
- final DataBaseAccess dataBaseAccess = new DataBaseAccessImpl();
final List<Map<String, String>> dataResult = dataBaseAccess.executeQuery("SELECT * FROM ACCOUNT WHERE CODE = ?",
answer ->
{
import static org.junit.Assert.*;
+import org.junit.Ignore;
import org.junit.Test;
+@Ignore
public class SessionHandleTest {
@Test
import static org.junit.Assert.*;
import java.time.LocalDateTime;
+import java.util.UUID;
import org.junit.Test;
public class SessionInfoTest {
+ private static final UUID UUID_VALUE = UUID.randomUUID();
private static final String USERNAME = "GUMARTINM";
private static final LocalDateTime LAST_SESSION = LocalDateTime.now();
@Test
public void shouldCallGetters() {
- SessionInfo sessionInfo = new SessionInfo(USERNAME, LAST_SESSION);
+ SessionInfo sessionInfo = new SessionInfo(UUID_VALUE, USERNAME, LAST_SESSION);
+ assertEquals(UUID_VALUE, sessionInfo.getUUID());
assertEquals(USERNAME, sessionInfo.getUsername());
assertEquals(LAST_SESSION, sessionInfo.getLastSessionTime());
}