diff --git a/pom.xml b/pom.xml index bfbb768..3e9af9f 100644 --- a/pom.xml +++ b/pom.xml @@ -22,7 +22,6 @@ mavor - src/main diff --git a/src/main/java/de/devloop/mavor/AuthenticatedServlet.java b/src/main/java/de/devloop/mavor/AuthenticatedServlet.java new file mode 100644 index 0000000..a9cf26e --- /dev/null +++ b/src/main/java/de/devloop/mavor/AuthenticatedServlet.java @@ -0,0 +1,26 @@ +package de.devloop.mavor; + +import java.io.IOException; + +import jakarta.servlet.ServletException; +import jakarta.servlet.http.HttpServlet; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; + +public class AuthenticatedServlet extends HttpServlet { + protected Session session; + + @Override + protected final void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { + session = new Session(req.getSession(true)); + if (!session.isAuthenticated()) { + resp.sendRedirect("/mavor/authenticate"); + } else { + doAuthenticatedGet(req, resp); + } + } + + protected void doAuthenticatedGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { + // nooooothing + } +} diff --git a/src/main/java/de/devloop/mavor/Session.java b/src/main/java/de/devloop/mavor/Session.java new file mode 100644 index 0000000..603307f --- /dev/null +++ b/src/main/java/de/devloop/mavor/Session.java @@ -0,0 +1,57 @@ +package de.devloop.mavor; + +import jakarta.servlet.http.HttpSession; + +public class Session { + private HttpSession session; + + private static final String ATTRIBUTE_USERNAME = "username"; + private static final String ATTRIBUTE_OAUTH_STATE = "oauth.state"; + private static final String ATTRIBUTE_OAUTH_TOKEN = "oauth.token"; + + public Session(HttpSession session) { + this.session = session; + } + + private String getSafeString(String parameter) { + Object value = session.getAttribute(parameter); + + if (value != null) { + return value.toString(); + } else { + return null; + } + } + + public Boolean isAuthenticated() { + return getUsername() != null; + } + + public String getUsername() { + return getSafeString(ATTRIBUTE_USERNAME); + } + + public void setUsername(String username) { + session.setAttribute(ATTRIBUTE_USERNAME, username); + } + + public void setOAuthState(String state) { + session.setAttribute(ATTRIBUTE_OAUTH_STATE, state); + } + + public String getOAuthState() { + return getSafeString(ATTRIBUTE_OAUTH_STATE); + } + + public void clearOAuthState() { + session.removeAttribute(ATTRIBUTE_OAUTH_STATE); + } + + public void setOAuthToken(String token) { + session.setAttribute(ATTRIBUTE_OAUTH_TOKEN, token); + } + + public String getOAuthToken() { + return getSafeString(ATTRIBUTE_OAUTH_TOKEN); + } +} diff --git a/src/main/de/devloop/mavor/annotation/AuthenticationRequired.java b/src/main/java/de/devloop/mavor/annotation/AuthenticationRequired.java similarity index 100% rename from src/main/de/devloop/mavor/annotation/AuthenticationRequired.java rename to src/main/java/de/devloop/mavor/annotation/AuthenticationRequired.java diff --git a/src/main/de/devloop/mavor/servlet/Authentication.java b/src/main/java/de/devloop/mavor/servlet/Authentication.java similarity index 100% rename from src/main/de/devloop/mavor/servlet/Authentication.java rename to src/main/java/de/devloop/mavor/servlet/Authentication.java diff --git a/src/main/de/devloop/mavor/servlet/Download.java b/src/main/java/de/devloop/mavor/servlet/Download.java similarity index 72% rename from src/main/de/devloop/mavor/servlet/Download.java rename to src/main/java/de/devloop/mavor/servlet/Download.java index 47c7550..ff531d6 100644 --- a/src/main/de/devloop/mavor/servlet/Download.java +++ b/src/main/java/de/devloop/mavor/servlet/Download.java @@ -19,22 +19,26 @@ public class Download extends AuthenticatedServlet { private static final String PARAMETER_ARTEFACT_ID = "artefactId"; private static final String PARAMETER_VERSION = "version"; + private static final String TEMP_DIR = "/home/damage/Temp/mavor"; + @Override protected void doAuthenticatedGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { + String site = req.getParameter(PARAMETER_SITE); String groupId = req.getParameter(PARAMETER_GROUP_ID); String artifactId = req.getParameter(PARAMETER_ARTEFACT_ID); String version = req.getParameter(PARAMETER_VERSION); + String artifact = String.format("%s:%s:%s", groupId, artifactId, version); + PrintStream out = new PrintStream(resp.getOutputStream()); MavenCli cli = new MavenCli(); System.setProperty("maven.multiModuleProjectDirectory", "/home/damage/Temp"); - cli.doMain(new String[]{"dependency:copy", "-Dartifact=com.google.code.gson:gson:2.11.0", "-DoutputDirectory=/home/damage/Temp"}, "/home/damage/Temp", out, out); + // TODO: does not work -> generate pom.xml in temp dir and use dependency:copy-dependencies? + System.setProperty("maven.repo.remote", site); + cli.doMain(new String[]{"dependency:copy", "-Dartifact=" + artifact, "-DoutputDirectory=/home/damage/Temp"}, "/home/damage/Temp", out, out); //RequestDispatcher view = req.getRequestDispatcher("/download.jsp"); - - //view.forward(req, resp); - } } diff --git a/src/main/de/devloop/mavor/servlet/Logout.java b/src/main/java/de/devloop/mavor/servlet/Logout.java similarity index 100% rename from src/main/de/devloop/mavor/servlet/Logout.java rename to src/main/java/de/devloop/mavor/servlet/Logout.java diff --git a/src/main/java/de/devloop/mavor/servlet/Main.java b/src/main/java/de/devloop/mavor/servlet/Main.java new file mode 100644 index 0000000..07aedf1 --- /dev/null +++ b/src/main/java/de/devloop/mavor/servlet/Main.java @@ -0,0 +1,22 @@ +package de.devloop.mavor.servlet; + +import java.io.IOException; + +import de.devloop.mavor.AuthenticatedServlet; +import jakarta.servlet.RequestDispatcher; +import jakarta.servlet.ServletException; +import jakarta.servlet.annotation.WebServlet; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; + +@WebServlet("") +public class Main extends AuthenticatedServlet { + + @Override + protected void doAuthenticatedGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { + req.setAttribute("username", session.getUsername()); + RequestDispatcher view = req.getRequestDispatcher("/main.jsp"); + + view.forward(req, resp); + } +} diff --git a/src/main/java/de/devloop/openid/AuthenticationUrl.java b/src/main/java/de/devloop/openid/AuthenticationUrl.java new file mode 100644 index 0000000..438440c --- /dev/null +++ b/src/main/java/de/devloop/openid/AuthenticationUrl.java @@ -0,0 +1,19 @@ +package de.devloop.openid; + +public class AuthenticationUrl { + private String url; + private String state; + + public AuthenticationUrl(String url, String state) { + this.url = url; + this.state = state; + } + + public String getUrl() { + return url; + } + + public String getState() { + return state; + } +} diff --git a/src/main/java/de/devloop/openid/OpenID.java b/src/main/java/de/devloop/openid/OpenID.java new file mode 100644 index 0000000..f002030 --- /dev/null +++ b/src/main/java/de/devloop/openid/OpenID.java @@ -0,0 +1,102 @@ +package de.devloop.openid; + +import java.io.IOException; +import java.net.URI; +import java.net.URISyntaxException; +import java.net.URLEncoder; +import java.net.http.HttpClient; +import java.net.http.HttpRequest; +import java.net.http.HttpRequest.BodyPublishers; +import java.net.http.HttpResponse; +import java.net.http.HttpResponse.BodyHandlers; +import java.nio.charset.StandardCharsets; +import java.util.HashMap; +import java.util.Map; +import java.util.UUID; + +import com.google.gson.Gson; + +public class OpenID { + private static final String CLIENT_ID = "vP9xF2s1yy2n6sR05jV6dguyMeOvIxCg1GarV71O"; + private static final String CLIENT_SECRET = "PrwGSMcucxYPkOdrb23jddWqyn31vphrxCUu9MGdLTCUnbk0OJI5oWCvO0khVhcnJNDbJaKWxNMxaC4bJ92jy8bDjtG6oaWG37qhuLRPMh5DKluZxsCMmCvQ8f9ZQckZ"; + + private static final String REDIRECT_URL = "http://localhost:8080/mavor/authenticate"; + + private static final String OAUTH_AUTH_URL = "https://auth.devloop.de/application/o/authorize/"; + private static final String OAUTH_TOKEN_URL = "https://auth.devloop.de/application/o/token/"; + private static final String OAUTH_USERINFO_URL = "https://auth.devloop.de/application/o/userinfo/"; + + public AuthenticationUrl getAuthenticationUrl() { + String state = UUID.randomUUID().toString(); + String url = String.format("%s?response_type=code&client_id=%s&redirect_uri=%s&state=%s&scope=openid email", OAUTH_AUTH_URL, CLIENT_ID, REDIRECT_URL, state); + return new AuthenticationUrl(url, state); + } + + private URI getUriObject(String url) throws OpenIdRequestException { + try { + return new URI(url); + } catch (URISyntaxException e) { + throw new OpenIdRequestException(String.format("Invalid URL: '%s'", url), e); + } + } + + public Token requestToken(String code) throws OpenIdRequestException { + URI tokenUrl = getUriObject(OAUTH_TOKEN_URL); + HashMap tokenParameter = new HashMap<>(); + tokenParameter.put("grant_type", "authorization_code"); + tokenParameter.put("client_id", CLIENT_ID); + tokenParameter.put("client_secret", CLIENT_SECRET); + tokenParameter.put("code", code); + tokenParameter.put("redirect_uri", REDIRECT_URL); + + HttpRequest tokenRequest = HttpRequest.newBuilder() + .uri(tokenUrl) + .header("Content-Type", "application/x-www-form-urlencoded") + .header("Accept", "application/json") + .POST(BodyPublishers.ofString(getFormDataAsString(tokenParameter))) + .build(); + HttpClient tokenClient = HttpClient.newHttpClient(); + HttpResponse tokenResponse; + try { + tokenResponse = tokenClient.send(tokenRequest, BodyHandlers.ofString()); + } catch (IOException | InterruptedException e) { + throw new OpenIdRequestException("Requesting access token failed", e); + } + + Gson gson = new Gson(); + return gson.fromJson(tokenResponse.body(), Token.class); + } + + public UserInfo requestUserInfo(Token token) throws OpenIdRequestException { + URI userInfoUrl = getUriObject(OAUTH_USERINFO_URL); + HttpRequest userInfoRequest = HttpRequest.newBuilder() + .uri(userInfoUrl) + .header("Accept", "application/json") + .header("Authorization", "Bearer " + token.getAccessToken()) + .GET() + .build(); + HttpClient userInfoClient = HttpClient.newHttpClient(); + HttpResponse userInfoResponse; + try { + userInfoResponse = userInfoClient.send(userInfoRequest, BodyHandlers.ofString()); + } catch (IOException | InterruptedException e) { + throw new OpenIdRequestException("Requesting user info failed", e); + } + + Gson gson = new Gson(); + return gson.fromJson(userInfoResponse.body(), UserInfo.class); + } + + private String getFormDataAsString(Map formData) { + StringBuilder formBodyBuilder = new StringBuilder(); + for (Map.Entry singleEntry : formData.entrySet()) { + if (formBodyBuilder.length() > 0) { + formBodyBuilder.append("&"); + } + formBodyBuilder.append(URLEncoder.encode(singleEntry.getKey(), StandardCharsets.UTF_8)); + formBodyBuilder.append("="); + formBodyBuilder.append(URLEncoder.encode(singleEntry.getValue(), StandardCharsets.UTF_8)); + } + return formBodyBuilder.toString(); + } +} diff --git a/src/main/java/de/devloop/openid/OpenIdRequestException.java b/src/main/java/de/devloop/openid/OpenIdRequestException.java new file mode 100644 index 0000000..cc41032 --- /dev/null +++ b/src/main/java/de/devloop/openid/OpenIdRequestException.java @@ -0,0 +1,7 @@ +package de.devloop.openid; + +public class OpenIdRequestException extends Exception { + public OpenIdRequestException(String message, Throwable cause) { + super(message, cause); + } +} diff --git a/src/main/java/de/devloop/openid/Token.java b/src/main/java/de/devloop/openid/Token.java new file mode 100644 index 0000000..2254ad9 --- /dev/null +++ b/src/main/java/de/devloop/openid/Token.java @@ -0,0 +1,18 @@ +package de.devloop.openid; + +import com.google.gson.annotations.SerializedName; + +public class Token { + + @SerializedName("access_token") + private String accessToken; + + public String getAccessToken() { + return accessToken; + } + + public void setAccessToken(String accessToken) { + this.accessToken = accessToken; + } + +} diff --git a/src/main/java/de/devloop/openid/UserInfo.java b/src/main/java/de/devloop/openid/UserInfo.java new file mode 100644 index 0000000..f34bf1f --- /dev/null +++ b/src/main/java/de/devloop/openid/UserInfo.java @@ -0,0 +1,15 @@ +package de.devloop.openid; + +public class UserInfo { + + private String email; + + public String getEmail() { + return email; + } + + public void setEmail(String email) { + this.email = email; + } + +}