From b251e4e4cb3a26e5746e8b486e0cda204e723b84 Mon Sep 17 00:00:00 2001 From: Stephan Richter Date: Thu, 14 Apr 2022 11:58:21 +0200 Subject: [PATCH] working on oidc auth --- pom.xml | 31 +++++ .../de/srsoftware/widerhall/Application.java | 42 +++++- .../srsoftware/widerhall/Configuration.java | 81 +++++++++++ .../de/srsoftware/widerhall/Constants.java | 6 + .../widerhall/{ => mail}/Forwarder.java | 2 +- .../widerhall/{ => mail}/ImapClient.java | 7 +- .../widerhall/{ => mail}/MessageHandler.java | 2 +- .../widerhall/{ => mail}/SmtpClient.java | 7 +- .../de/srsoftware/widerhall/web/Index.java | 43 ++++++ .../de/srsoftware/widerhall/web/Login.java | 127 ++++++++++++++++++ .../de/srsoftware/widerhall/web/Rest.java | 21 +++ .../srsoftware/widerhall/web/tags/Header.java | 10 ++ .../srsoftware/widerhall/web/tags/Page.java | 11 ++ 13 files changed, 371 insertions(+), 19 deletions(-) create mode 100644 src/main/java/de/srsoftware/widerhall/Configuration.java rename src/main/java/de/srsoftware/widerhall/{ => mail}/Forwarder.java (96%) rename src/main/java/de/srsoftware/widerhall/{ => mail}/ImapClient.java (96%) rename src/main/java/de/srsoftware/widerhall/{ => mail}/MessageHandler.java (82%) rename src/main/java/de/srsoftware/widerhall/{ => mail}/SmtpClient.java (91%) create mode 100644 src/main/java/de/srsoftware/widerhall/web/Index.java create mode 100644 src/main/java/de/srsoftware/widerhall/web/Login.java create mode 100644 src/main/java/de/srsoftware/widerhall/web/Rest.java create mode 100644 src/main/java/de/srsoftware/widerhall/web/tags/Header.java create mode 100644 src/main/java/de/srsoftware/widerhall/web/tags/Page.java diff --git a/pom.xml b/pom.xml index d1add8b..659ab99 100644 --- a/pom.xml +++ b/pom.xml @@ -7,6 +7,18 @@ org.example Widerhall 1.0-SNAPSHOT + + + + org.apache.maven.plugins + maven-compiler-plugin + + 16 + 16 + + + + 17 @@ -14,6 +26,25 @@ + + + org.eclipse.jetty + jetty-server + 10.0.9 + + + + org.eclipse.jetty + jetty-servlet + 10.0.9 + + + + de.srsoftware + tools + 1.1.18 + + com.sun.mail javax.mail diff --git a/src/main/java/de/srsoftware/widerhall/Application.java b/src/main/java/de/srsoftware/widerhall/Application.java index 32398b3..e531bcf 100644 --- a/src/main/java/de/srsoftware/widerhall/Application.java +++ b/src/main/java/de/srsoftware/widerhall/Application.java @@ -1,5 +1,15 @@ package de.srsoftware.widerhall; +import de.srsoftware.widerhall.mail.Forwarder; +import de.srsoftware.widerhall.mail.ImapClient; +import de.srsoftware.widerhall.mail.MessageHandler; +import de.srsoftware.widerhall.web.Index; +import de.srsoftware.widerhall.web.Login; +import de.srsoftware.widerhall.web.Rest; +import org.eclipse.jetty.server.Connector; +import org.eclipse.jetty.server.Server; +import org.eclipse.jetty.server.ServerConnector; +import org.eclipse.jetty.servlet.ServletContextHandler; import org.json.simple.JSONObject; import org.json.simple.parser.JSONParser; import org.json.simple.parser.ParseException; @@ -7,17 +17,35 @@ import org.json.simple.parser.ParseException; import java.io.File; import java.io.IOException; import java.nio.file.Files; +import java.nio.file.Path; +import java.util.Map; +import static de.srsoftware.widerhall.Constants.*; public class Application { - public static void main(String[] args) throws IOException, ParseException { - var parser = new JSONParser(); - var config = Files.readString(new File("/tmp/config.json").toPath()); - JSONObject json = (JSONObject) parser.parse(config); + public static void main(String[] args) throws Exception { + var config = Configuration.setFile(new File("/tmp/config.json")); + //startMailSystem(json); + startWebserver(config); + } + + private static void startWebserver(Configuration config) throws Exception { + var server = new Server(); + var connector = new ServerConnector(server); + connector.setPort(config.serverPort()); + server.setConnectors(new Connector[]{connector}); + ServletContextHandler context = new ServletContextHandler(server, "/"); + context.addServlet(Rest.class,"/api"); + context.addServlet(Login.class,"/login"); + context.addServlet(Index.class,"/"); + + server.start(); + } + private static void startMailSystem(JSONObject json) { MessageHandler forward = new Forwarder(json); - new ImapClient(json) - .addListener(forward) - .start(); + new ImapClient(json) + .addListener(forward) + .start(); } } diff --git a/src/main/java/de/srsoftware/widerhall/Configuration.java b/src/main/java/de/srsoftware/widerhall/Configuration.java new file mode 100644 index 0000000..25a19da --- /dev/null +++ b/src/main/java/de/srsoftware/widerhall/Configuration.java @@ -0,0 +1,81 @@ +package de.srsoftware.widerhall; + +import org.json.simple.JSONObject; +import org.json.simple.parser.JSONParser; +import org.json.simple.parser.ParseException; + +import java.io.File; +import java.io.IOException; +import java.net.MalformedURLException; +import java.net.URL; +import java.nio.file.Files; +import static de.srsoftware.widerhall.Constants.*; +public class Configuration { + private static Configuration singleton = null; + private JSONObject data; + private final File file; + + public Configuration(File configFile) throws IOException, ParseException { + this.file = configFile; + if (!configFile.exists()){ + setDefaults(); + save(); + } + var content = Files.readString(configFile.toPath()); + data = (JSONObject) new JSONParser().parse(content); + } + + public static Configuration setFile(File file) throws IOException, ParseException { + singleton = new Configuration(file); + return singleton; + } + + public static Configuration instance() { + return singleton; + } + + private void setDefaults() throws MalformedURLException { + if (data == null) data = new JSONObject(); + serverPort(); + tokenUrl(); + loginUrl(); + baseUrl(); + clientId(); + clientSecret(); + } + + private void save() throws IOException { + Files.writeString(file.toPath(),data.toJSONString()); + } + + public int serverPort() { + if (!data.containsKey(PORT)) data.put(PORT,80L); + var o = data.get(PORT); + return (int) (long) o; + } + + public URL tokenUrl() throws MalformedURLException { + if (!data.containsKey(TOKEN_URL)) data.put(TOKEN_URL,"http://localhost:"+serverPort()+"/oauth/token"); + return new URL((String) data.get(TOKEN_URL)); + } + + public String loginUrl() { + if (!data.containsKey(LOGIN_URL)) data.put(LOGIN_URL,"http://localhost:"+serverPort()+"/oauth/login"); + return (String) data.get(LOGIN_URL); + } + + public String baseUrl() { + if (!data.containsKey(BASE_URL)) data.put(BASE_URL,"http://localhost"); + return (String) data.get(BASE_URL); + } + + public String clientId() { + if (!data.containsKey(Constants.CLIENT_ID)) data.put(CLIENT_ID,"widerhall"); + return (String) data.get(CLIENT_ID); + } + + public Object clientSecret() { + if (!data.containsKey(Constants.CLIENT_SECRET)) data.put(CLIENT_SECRET,"changeme"); + return (String) data.get(CLIENT_SECRET); + } +} diff --git a/src/main/java/de/srsoftware/widerhall/Constants.java b/src/main/java/de/srsoftware/widerhall/Constants.java index 796f2ba..504771a 100644 --- a/src/main/java/de/srsoftware/widerhall/Constants.java +++ b/src/main/java/de/srsoftware/widerhall/Constants.java @@ -7,4 +7,10 @@ public class Constants { public static final String USER = "user"; public static final String PASSWORD = "password"; public static final String INBOX = "inbox"; + public static final Object PORT = "port"; + public static final String TOKEN_URL = "token_url"; + public static final String LOGIN_URL = "login_url"; + public static final String BASE_URL = "base_url"; + public static final String CLIENT_ID = "client_id"; + public static final String CLIENT_SECRET = "client_secret"; } diff --git a/src/main/java/de/srsoftware/widerhall/Forwarder.java b/src/main/java/de/srsoftware/widerhall/mail/Forwarder.java similarity index 96% rename from src/main/java/de/srsoftware/widerhall/Forwarder.java rename to src/main/java/de/srsoftware/widerhall/mail/Forwarder.java index 2bd48f1..9f1c687 100644 --- a/src/main/java/de/srsoftware/widerhall/Forwarder.java +++ b/src/main/java/de/srsoftware/widerhall/mail/Forwarder.java @@ -1,4 +1,4 @@ -package de.srsoftware.widerhall; +package de.srsoftware.widerhall.mail; import org.json.simple.JSONObject; import org.slf4j.Logger; diff --git a/src/main/java/de/srsoftware/widerhall/ImapClient.java b/src/main/java/de/srsoftware/widerhall/mail/ImapClient.java similarity index 96% rename from src/main/java/de/srsoftware/widerhall/ImapClient.java rename to src/main/java/de/srsoftware/widerhall/mail/ImapClient.java index 283b97a..082402b 100644 --- a/src/main/java/de/srsoftware/widerhall/ImapClient.java +++ b/src/main/java/de/srsoftware/widerhall/mail/ImapClient.java @@ -1,8 +1,7 @@ -package de.srsoftware.widerhall; +package de.srsoftware.widerhall.mail; -import com.sun.mail.iap.ProtocolException; import com.sun.mail.imap.IMAPFolder; -import com.sun.mail.imap.protocol.IMAPProtocol; +import de.srsoftware.widerhall.Constants; import org.json.simple.JSONObject; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -106,7 +105,7 @@ public class ImapClient { } } } - ImapClient(JSONObject config){ + public ImapClient(JSONObject config){ this.config = config; } diff --git a/src/main/java/de/srsoftware/widerhall/MessageHandler.java b/src/main/java/de/srsoftware/widerhall/mail/MessageHandler.java similarity index 82% rename from src/main/java/de/srsoftware/widerhall/MessageHandler.java rename to src/main/java/de/srsoftware/widerhall/mail/MessageHandler.java index 7aa7663..dc54f53 100644 --- a/src/main/java/de/srsoftware/widerhall/MessageHandler.java +++ b/src/main/java/de/srsoftware/widerhall/mail/MessageHandler.java @@ -1,4 +1,4 @@ -package de.srsoftware.widerhall; +package de.srsoftware.widerhall.mail; import javax.mail.Message; import javax.mail.MessagingException; diff --git a/src/main/java/de/srsoftware/widerhall/SmtpClient.java b/src/main/java/de/srsoftware/widerhall/mail/SmtpClient.java similarity index 91% rename from src/main/java/de/srsoftware/widerhall/SmtpClient.java rename to src/main/java/de/srsoftware/widerhall/mail/SmtpClient.java index a56b23c..3b543a8 100644 --- a/src/main/java/de/srsoftware/widerhall/SmtpClient.java +++ b/src/main/java/de/srsoftware/widerhall/mail/SmtpClient.java @@ -1,18 +1,13 @@ -package de.srsoftware.widerhall; +package de.srsoftware.widerhall.mail; import org.json.simple.JSONObject; -import org.json.simple.parser.JSONParser; -import org.json.simple.parser.ParseException; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import javax.mail.*; import javax.mail.internet.InternetAddress; import javax.mail.internet.MimeMessage; -import java.io.File; -import java.io.IOException; import java.io.UnsupportedEncodingException; -import java.nio.file.Files; import java.util.Date; import java.util.Map; import java.util.Properties; diff --git a/src/main/java/de/srsoftware/widerhall/web/Index.java b/src/main/java/de/srsoftware/widerhall/web/Index.java new file mode 100644 index 0000000..7a76cda --- /dev/null +++ b/src/main/java/de/srsoftware/widerhall/web/Index.java @@ -0,0 +1,43 @@ +package de.srsoftware.widerhall.web; + +import de.srsoftware.tools.Tag; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import javax.servlet.ServletException; +import javax.servlet.http.HttpServlet; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; + +public class Index extends HttpServlet { + + private static final Logger LOG = LoggerFactory.getLogger(Index.class); + + @Override + protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { + resp.setContentType("text/html"); + resp.setStatus(HttpServletResponse.SC_OK); + String auth = req.getHeader("Authorization"); + if (auth == null) { + resp.sendRedirect("login"); + return; + } + LOG.debug("Authorization: {}",auth); + + resp.getWriter().println(page(auth)); + + } + + private Tag head() { + return new Tag("meta") + .attr("charset","utf-8") + .addTo(new Tag("head")); + + } + + private Tag page(String auth) { + var body = new Tag("body").content(auth); + return body.addTo(head().addTo(new Tag("html"))); + } +} diff --git a/src/main/java/de/srsoftware/widerhall/web/Login.java b/src/main/java/de/srsoftware/widerhall/web/Login.java new file mode 100644 index 0000000..eb82a73 --- /dev/null +++ b/src/main/java/de/srsoftware/widerhall/web/Login.java @@ -0,0 +1,127 @@ +package de.srsoftware.widerhall.web; + +import de.srsoftware.widerhall.Configuration; +import de.srsoftware.widerhall.web.tags.Page; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import javax.net.ssl.HttpsURLConnection; +import javax.servlet.http.HttpServlet; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import java.io.BufferedReader; +import java.io.DataOutputStream; +import java.io.IOException; +import java.io.InputStreamReader; +import java.net.URLEncoder; +import java.nio.charset.StandardCharsets; +import java.util.Map; +import java.util.stream.Collectors; + +public class Login extends HttpServlet { + + private static final Logger LOG = LoggerFactory.getLogger(Login.class); + private final Configuration config; + + public Login(){ + this.config = Configuration.instance(); + LOG.debug("Creating new instance of Login.class"); + } + + @Override + protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws IOException { + var error = req.getParameter("error"); + if (error != null){ + var description = req.getParameter("error_description"); + sendError(resp,error+": "+description); + return; + } + LOG.debug("params: {}",req.getParameterMap()); + var code = req.getParameter("code"); + if (code != null){ + getTokenFor(code,resp); + resp.getWriter().println(new Page("rceived code: "+code)); + return; + } + resp.sendRedirect(loginUrl()); + } + + private static String urlEncode(Map data) { + String params = data.entrySet() + .stream() + .map(entry -> encode(entry.getKey()) + "=" + encode(entry.getValue())) + .collect(Collectors.joining("&")); + return params; + } + + private static String encode(Object value) { + return URLEncoder.encode(value.toString(),StandardCharsets.UTF_8); + } + + private void getTokenFor(String code, HttpServletResponse resp) throws IOException { + var url = config.tokenUrl(); + LOG.debug("Sending 'POST' request to URL '{}'",url); + HttpsURLConnection httpClient = (HttpsURLConnection) url.openConnection(); + + //add reuqest header + httpClient.setRequestMethod("POST"); + httpClient.setRequestProperty( "Content-Type", "application/x-www-form-urlencoded"); + httpClient.setRequestProperty( "Accept", "*/*" ); + //httpClient.setRequestProperty("User-Agent", "Mozilla/5.0"); + //httpClient.setRequestProperty("Accept-Language", "en-US,en;q=0.5"); + + String urlParameters = urlEncode(Map.of( + "code",code, + "client_id",config.clientId(), + "client_secret",config.clientSecret(), + "grant_type","authorization_code")); + + LOG.debug("Posting parameters '{}'",urlParameters); + + // Send post request + httpClient.setDoOutput(true); + httpClient.setDoInput(true); + try (DataOutputStream wr = new DataOutputStream(httpClient.getOutputStream())) { + wr.writeBytes(urlParameters); + wr.flush(); + } + + int responseCode = httpClient.getResponseCode(); + LOG.debug("Response Code: {}",responseCode); + + try (BufferedReader in = new BufferedReader(new InputStreamReader(httpClient.getInputStream()))) { + + String line; + StringBuilder response = new StringBuilder(); + + while ((line = in.readLine()) != null) { + response.append(line); + } + + //print result + //System.out.println(response.toString()); + resp.getWriter().println(response); + + } + } + + private void sendError(HttpServletResponse resp, String error) throws IOException { + LOG.debug("error: {}",error); + resp.sendError(HttpServletResponse.SC_BAD_REQUEST,error); + } + + private String loginUrl() { + return config.loginUrl()+"?"+urlEncode(Map.of( + "response_type","code", + "client_id",config.clientId(), + "state",123456, + "redirect_uri",redirectUri(), + "scope","openid" + )); + } + + private String redirectUri() { + int port = config.serverPort(); + return config.baseUrl()+(port == 80 ? "" : ":"+port)+"/login"; + } +} diff --git a/src/main/java/de/srsoftware/widerhall/web/Rest.java b/src/main/java/de/srsoftware/widerhall/web/Rest.java new file mode 100644 index 0000000..1b82471 --- /dev/null +++ b/src/main/java/de/srsoftware/widerhall/web/Rest.java @@ -0,0 +1,21 @@ +package de.srsoftware.widerhall.web; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import javax.servlet.ServletException; +import javax.servlet.http.HttpServlet; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; + +public class Rest extends HttpServlet { + + private static final Logger LOG = LoggerFactory.getLogger(Rest.class); + @Override + protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { + String method = req.getMethod(); + LOG.debug("GET {}"+method); + + } +} diff --git a/src/main/java/de/srsoftware/widerhall/web/tags/Header.java b/src/main/java/de/srsoftware/widerhall/web/tags/Header.java new file mode 100644 index 0000000..a302815 --- /dev/null +++ b/src/main/java/de/srsoftware/widerhall/web/tags/Header.java @@ -0,0 +1,10 @@ +package de.srsoftware.widerhall.web.tags; + +import de.srsoftware.tools.Tag; + +public class Header extends Tag { + public Header() { + super("head"); + new Tag("meta").attr("charset","utf-8").addTo(this); + } +} diff --git a/src/main/java/de/srsoftware/widerhall/web/tags/Page.java b/src/main/java/de/srsoftware/widerhall/web/tags/Page.java new file mode 100644 index 0000000..4a079ac --- /dev/null +++ b/src/main/java/de/srsoftware/widerhall/web/tags/Page.java @@ -0,0 +1,11 @@ +package de.srsoftware.widerhall.web.tags; + +import de.srsoftware.tools.Tag; + +public class Page extends Tag { + public Page(String content) { + super("html"); + new Header().addTo(this); + new Tag("body").content(content).addTo(this); + } +}