22 changed files with 173 additions and 401 deletions
@ -1,17 +1,23 @@ |
|||||||
/* © SRSoftware 2024 */ |
/* © SRSoftware 2024 */ |
||||||
package de.srsoftware.oidc.server; |
package de.srsoftware.oidc.app; |
||||||
|
|
||||||
|
|
||||||
import com.sun.net.httpserver.HttpServer; |
import com.sun.net.httpserver.HttpServer; |
||||||
|
import de.srsoftware.oidc.backend.Backend; |
||||||
|
import de.srsoftware.oidc.web.Forward; |
||||||
import de.srsoftware.oidc.web.StaticPages; |
import de.srsoftware.oidc.web.StaticPages; |
||||||
import java.net.InetSocketAddress; |
import java.net.InetSocketAddress; |
||||||
import java.util.concurrent.Executors; |
import java.util.concurrent.Executors; |
||||||
|
|
||||||
public class Application { |
public class Application { |
||||||
|
public static final String STATIC_PATH = "/web"; |
||||||
|
public static final String INDEX = STATIC_PATH + "/index.html"; |
||||||
|
|
||||||
public static void main(String[] args) throws Exception { |
public static void main(String[] args) throws Exception { |
||||||
HttpServer server = HttpServer.create(new InetSocketAddress(8080), 0); |
HttpServer server = HttpServer.create(new InetSocketAddress(8080), 0); |
||||||
new StaticPages().bindPath("/static").on(server); |
new StaticPages().bindPath(STATIC_PATH).on(server); |
||||||
new LanguageDirector("/static").bindPath("/").on(server); |
new Forward(INDEX).bindPath("/").on(server); |
||||||
|
new Backend().bindPath("/api").on(server); |
||||||
server.setExecutor(Executors.newCachedThreadPool()); |
server.setExecutor(Executors.newCachedThreadPool()); |
||||||
server.start(); |
server.start(); |
||||||
} |
} |
@ -0,0 +1,44 @@ |
|||||||
|
/* © SRSoftware 2024 */ |
||||||
|
package de.srsoftware.oidc.backend; |
||||||
|
|
||||||
|
import static java.net.HttpURLConnection.HTTP_NOT_FOUND; |
||||||
|
import static java.net.HttpURLConnection.HTTP_UNAUTHORIZED; |
||||||
|
|
||||||
|
import com.sun.net.httpserver.HttpExchange; |
||||||
|
import de.srsoftware.oidc.api.PathHandler; |
||||||
|
import java.io.IOException; |
||||||
|
import java.util.Optional; |
||||||
|
|
||||||
|
public class Backend extends PathHandler { |
||||||
|
@Override |
||||||
|
public void handle(HttpExchange ex) throws IOException { |
||||||
|
String path = relativePath(ex); |
||||||
|
String method = ex.getRequestMethod(); |
||||||
|
System.out.printf("%s %s…", method, path); |
||||||
|
|
||||||
|
if ("login".equals(path)) { |
||||||
|
doLogin(ex); |
||||||
|
return; |
||||||
|
} |
||||||
|
var token = getAuthToken(ex); |
||||||
|
if (token.isEmpty()) { |
||||||
|
emptyResponse(HTTP_UNAUTHORIZED, ex); |
||||||
|
System.err.println("unauthorized"); |
||||||
|
return; |
||||||
|
} |
||||||
|
System.err.println("not implemented"); |
||||||
|
ex.sendResponseHeaders(HTTP_NOT_FOUND, 0); |
||||||
|
ex.getResponseBody().close(); |
||||||
|
} |
||||||
|
|
||||||
|
private void doLogin(HttpExchange ex) throws IOException { |
||||||
|
Optional<String> user = getHeader(ex, "login-username"); |
||||||
|
Optional<String> pass = getHeader(ex, "login-password"); |
||||||
|
System.out.printf("%s : %s", user, pass); |
||||||
|
emptyResponse(HTTP_UNAUTHORIZED, ex); |
||||||
|
} |
||||||
|
|
||||||
|
private Optional<String> getAuthToken(HttpExchange ex) { |
||||||
|
return getHeader(ex, "Authorization"); |
||||||
|
} |
||||||
|
} |
@ -1,20 +0,0 @@ |
|||||||
/* © SRSoftware 2024 */ |
|
||||||
package de.srsoftware.oidc.light; |
|
||||||
|
|
||||||
public class Constants { |
|
||||||
public static final String BODY = "body"; |
|
||||||
public static final String EMAIL = "email"; |
|
||||||
public static final String ERR_PAGE_NOT_FOUND = "page_not_found"; |
|
||||||
public static final String ERR_REDIRECT_FAILED = "redirect_failed"; |
|
||||||
public static final String HEAD = "head"; |
|
||||||
public static final String MESSAGES = "messages.txt"; |
|
||||||
public static final String PAGE_LOGIN = "login"; |
|
||||||
public static final String PAGE_START = "start"; |
|
||||||
public static final String PAGE_WELCOME = "welcome"; |
|
||||||
public static final String PASSWORD = "password"; |
|
||||||
public static final String TARGET = "target"; |
|
||||||
public static final String TITLE = "title"; |
|
||||||
public static final String TITLE_LOGIN = "title_login"; |
|
||||||
public static final String TITLE_WELCOME = "title_welcom"; |
|
||||||
public static final String USER = "user"; |
|
||||||
} |
|
@ -1,178 +0,0 @@ |
|||||||
/* © SRSoftware 2024 */ |
|
||||||
package de.srsoftware.oidc.light; |
|
||||||
|
|
||||||
import static de.srsoftware.oidc.light.Constants.*; |
|
||||||
import static de.srsoftware.oidc.light.Templates.braced; |
|
||||||
|
|
||||||
import de.srsoftware.oidc.api.User; |
|
||||||
import jakarta.servlet.ServletException; |
|
||||||
import jakarta.servlet.annotation.WebServlet; |
|
||||||
import jakarta.servlet.http.HttpServlet; |
|
||||||
import jakarta.servlet.http.HttpServletRequest; |
|
||||||
import jakarta.servlet.http.HttpServletResponse; |
|
||||||
import jakarta.servlet.http.HttpSession; |
|
||||||
import java.io.IOException; |
|
||||||
import java.util.*; |
|
||||||
import java.util.stream.Collectors; |
|
||||||
import org.slf4j.Logger; |
|
||||||
import org.slf4j.LoggerFactory; |
|
||||||
|
|
||||||
@WebServlet("/web") |
|
||||||
public class LightOICD extends HttpServlet { |
|
||||||
private static final Logger LOG = LoggerFactory.getLogger(LightOICD.class); |
|
||||||
private static final Templates templates; |
|
||||||
|
|
||||||
static { |
|
||||||
try { |
|
||||||
templates = Templates.singleton(); |
|
||||||
} catch (IOException e) { |
|
||||||
throw new RuntimeException(e); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
@Override |
|
||||||
public void doGet(HttpServletRequest req, HttpServletResponse resp) throws IOException, ServletException { |
|
||||||
var path = relativePath(req); |
|
||||||
var optUser = loadUser(req); |
|
||||||
handleGet(path, optUser, req, resp).ifPresent(resp.getWriter()::println); |
|
||||||
} |
|
||||||
|
|
||||||
|
|
||||||
@Override |
|
||||||
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { |
|
||||||
var path = relativePath(req); |
|
||||||
var optUser = loadUser(req); |
|
||||||
handlePost(path, optUser, req, resp).ifPresent(resp.getWriter()::println); |
|
||||||
} |
|
||||||
|
|
||||||
public List<String> relativePath(HttpServletRequest req) { |
|
||||||
var cp = req.getContextPath(); |
|
||||||
var uri = req.getRequestURI(); |
|
||||||
if (uri.startsWith(cp)) uri = uri.substring(cp.length()); // strip context path → relative path!
|
|
||||||
var path = Arrays.stream(uri.split("/")).skip(1).collect(Collectors.toList()); |
|
||||||
if (path.isEmpty()) path.add(PAGE_START); |
|
||||||
return path; |
|
||||||
} |
|
||||||
|
|
||||||
private Optional<String> handleGet(List<String> path, Optional<User> optUser, HttpServletRequest req, HttpServletResponse resp) { |
|
||||||
String token = path.remove(0); |
|
||||||
if (optUser.isPresent()) { |
|
||||||
var user = optUser.get(); |
|
||||||
switch (token) { |
|
||||||
case PAGE_START: |
|
||||||
return pageStart(user, req, resp); |
|
||||||
case PAGE_WELCOME: |
|
||||||
return pageWelcome(user, req, resp); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
switch (token) { |
|
||||||
case PAGE_LOGIN: |
|
||||||
return pageLogin(req, resp); |
|
||||||
case PAGE_START: |
|
||||||
case PAGE_WELCOME: |
|
||||||
return redirect(resp, PAGE_LOGIN); |
|
||||||
} |
|
||||||
return templates.message(ERR_PAGE_NOT_FOUND); |
|
||||||
} |
|
||||||
|
|
||||||
|
|
||||||
private Optional<String> handlePost(List<String> path, Optional<User> optUser, HttpServletRequest req, HttpServletResponse resp) { |
|
||||||
String token = path.remove(0); |
|
||||||
if (optUser.isPresent()) { |
|
||||||
var user = optUser.get(); |
|
||||||
switch (token) { |
|
||||||
case PAGE_START: |
|
||||||
return pageStart(user, req, resp); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
switch (token) { |
|
||||||
case PAGE_LOGIN: |
|
||||||
return postLogin(req, resp); |
|
||||||
case PAGE_START: |
|
||||||
return redirect(resp, PAGE_LOGIN); |
|
||||||
} |
|
||||||
return templates.message(ERR_PAGE_NOT_FOUND); |
|
||||||
} |
|
||||||
|
|
||||||
private Optional<User> loadUser(HttpServletRequest req) { |
|
||||||
HttpSession session = req.getSession(); |
|
||||||
if (session.getAttribute(USER) instanceof User user) return Optional.of(user); |
|
||||||
return Optional.empty(); |
|
||||||
} |
|
||||||
|
|
||||||
|
|
||||||
private Optional<String> pageLogin(HttpServletRequest req, HttpServletResponse resp) { |
|
||||||
LOG.debug("pageLogin(…)"); |
|
||||||
try { |
|
||||||
var title = templates.message(TITLE_LOGIN).orElse(TITLE_LOGIN); |
|
||||||
var head = templates.get("head.snippet", Map.of(TITLE, title)).get(); |
|
||||||
var login = templates.get("login.snippet", Map.of(USER, "Darling", EMAIL, "", PASSWORD, "")).get(); |
|
||||||
var page = templates.get("scaffold.html", Map.of(BODY, login, HEAD, head)).get(); |
|
||||||
resp.setContentType("text/html"); |
|
||||||
resp.getWriter().println(page); |
|
||||||
return Optional.empty(); |
|
||||||
} catch (Exception e) { |
|
||||||
return Optional.of(e.getMessage()); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
private Optional<String> pageStart(User user, HttpServletRequest req, HttpServletResponse resp) { |
|
||||||
LOG.debug("pageStart(…)"); |
|
||||||
return Optional.empty(); |
|
||||||
} |
|
||||||
|
|
||||||
private Optional<String> pageWelcome(User user, HttpServletRequest req, HttpServletResponse resp) { |
|
||||||
LOG.debug("pageWelcome(…)"); |
|
||||||
try { |
|
||||||
var title = templates.message(TITLE_WELCOME).orElse(TITLE_WELCOME); |
|
||||||
var head = templates.get("head.snippet", Map.of(TITLE, title)).get(); |
|
||||||
var login = templates.get("welcome.snippet", Map.of(USER, "Darling", EMAIL, "", PASSWORD, "")).get(); |
|
||||||
var page = templates.get("scaffold.html", Map.of(BODY, login, HEAD, head)).get(); |
|
||||||
resp.setContentType("text/html"); |
|
||||||
resp.getWriter().println(page); |
|
||||||
return Optional.empty(); |
|
||||||
} catch (Exception e) { |
|
||||||
return Optional.of(e.getMessage()); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
private Optional<String> postLogin(HttpServletRequest req, HttpServletResponse resp) { |
|
||||||
LOG.debug("postLogin(…)"); |
|
||||||
var email = req.getParameter(EMAIL); |
|
||||||
if (braced(EMAIL).equals(email)) email = ""; |
|
||||||
var pass = req.getParameter(PASSWORD); |
|
||||||
var user = tryLogin(email, pass); |
|
||||||
if (user.isPresent()) { |
|
||||||
req.getSession().setAttribute(USER, user.get()); |
|
||||||
return redirect(resp, PAGE_WELCOME); |
|
||||||
} |
|
||||||
try { |
|
||||||
var title = templates.message(TITLE_LOGIN).orElse(TITLE_LOGIN); |
|
||||||
var head = templates.get("head.snippet", Map.of(TITLE, title)).get(); |
|
||||||
var login = templates.get("login.snippet", Map.of(USER, "Darling", EMAIL, email, PASSWORD, "")).get(); |
|
||||||
var page = templates.get("scaffold.html", Map.of(BODY, login, HEAD, head)).get(); |
|
||||||
resp.setContentType("text/html"); |
|
||||||
resp.getWriter().println(page); |
|
||||||
return Optional.empty(); |
|
||||||
} catch (Exception e) { |
|
||||||
return Optional.of(e.getMessage()); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
private Optional<User> tryLogin(String email, String pass) { |
|
||||||
if (email == null || pass == null) return Optional.empty(); |
|
||||||
if (email.equals(pass)) return Optional.of(new User()); |
|
||||||
return Optional.empty(); |
|
||||||
} |
|
||||||
|
|
||||||
private Optional<String> redirect(HttpServletResponse resp, String path) { |
|
||||||
try { |
|
||||||
resp.sendRedirect(path); |
|
||||||
} catch (IOException e) { |
|
||||||
return templates.message(ERR_REDIRECT_FAILED, Map.of(TARGET, path)); |
|
||||||
} |
|
||||||
return Optional.empty(); |
|
||||||
} |
|
||||||
} |
|
@ -1,94 +0,0 @@ |
|||||||
/* © SRSoftware 2024 */ |
|
||||||
package de.srsoftware.oidc.light; |
|
||||||
|
|
||||||
import static de.srsoftware.oidc.light.Constants.MESSAGES; |
|
||||||
|
|
||||||
import java.io.File; |
|
||||||
import java.io.FileNotFoundException; |
|
||||||
import java.io.IOException; |
|
||||||
import java.nio.file.Files; |
|
||||||
import java.nio.file.Path; |
|
||||||
import java.util.HashMap; |
|
||||||
import java.util.Map; |
|
||||||
import java.util.Optional; |
|
||||||
import org.slf4j.Logger; |
|
||||||
import org.slf4j.LoggerFactory; |
|
||||||
|
|
||||||
public class Templates { |
|
||||||
private static Templates singleton = null; |
|
||||||
private static Logger LOG = LoggerFactory.getLogger(Templates.class); |
|
||||||
private Path dir = searchTemplates(); |
|
||||||
private Map<String, String> messages = null; |
|
||||||
|
|
||||||
public Templates() throws FileNotFoundException { |
|
||||||
} |
|
||||||
|
|
||||||
private static Path searchTemplates() throws FileNotFoundException { |
|
||||||
return searchTemplates(new File(System.getProperty("user.dir"))).map(File::toPath).orElseThrow(() -> new FileNotFoundException("Missing template directory")); |
|
||||||
} |
|
||||||
|
|
||||||
private static Optional<File> searchTemplates(File dir) { |
|
||||||
if (dir.isDirectory()) { |
|
||||||
var children = dir.listFiles(); |
|
||||||
for (File child : children) { |
|
||||||
if (child.isDirectory()) { |
|
||||||
if (child.getName().equals("templates")) return Optional.of(child); |
|
||||||
var inner = searchTemplates(child); |
|
||||||
if (inner.isPresent()) return inner; |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
||||||
return Optional.empty(); |
|
||||||
} |
|
||||||
|
|
||||||
public static Templates singleton() throws IOException { |
|
||||||
if (singleton == null) singleton = new Templates(); |
|
||||||
return singleton; |
|
||||||
} |
|
||||||
|
|
||||||
public Optional<String> get(String path) { |
|
||||||
return get(path, Map.of()); |
|
||||||
} |
|
||||||
|
|
||||||
public Optional<String> get(String path, Map<String, String> replacements) { |
|
||||||
var file = dir.resolve(path); |
|
||||||
try { |
|
||||||
return Optional.of(Files.readString(file)).map(s -> replaceKeys(s, replacements)); |
|
||||||
} catch (IOException e) { |
|
||||||
LOG.warn("Failed to read {}", path, e); |
|
||||||
return Optional.empty(); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
private String replaceKeys(String text, Map<String, String> replacements) { |
|
||||||
for (Map.Entry<String, String> replacement : replacements.entrySet()) text = text.replace(braced(replacement.getKey()), replacement.getValue()); |
|
||||||
return text; |
|
||||||
} |
|
||||||
|
|
||||||
public Optional<String> message(String code) { |
|
||||||
return message(code, Map.of()); |
|
||||||
} |
|
||||||
|
|
||||||
public Optional<String> message(String code, Map<String, String> replacements) { |
|
||||||
if (this.messages == null) { |
|
||||||
get(MESSAGES).map(s -> s.split("\n")).ifPresent(this::setMessages); |
|
||||||
} |
|
||||||
return Optional.ofNullable(messages.get(code)).map(text -> replaceKeys(text, replacements)); |
|
||||||
} |
|
||||||
|
|
||||||
private void setMessages(String[] lines) { |
|
||||||
this.messages = new HashMap<>(); |
|
||||||
for (String line : lines) { |
|
||||||
var parts = line.split(" ", 2); |
|
||||||
if (parts.length < 2) { |
|
||||||
LOG.warn("Invalid format in {} file, skipped {}", MESSAGES, line); |
|
||||||
continue; |
|
||||||
} |
|
||||||
messages.put(parts[0], parts[1]); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
public static String braced(String key) { |
|
||||||
return String.join(key, "{", "}"); |
|
||||||
} |
|
||||||
} |
|
@ -1,16 +0,0 @@ |
|||||||
<meta charset="UTF-8"> |
|
||||||
<title>{title}</title> |
|
||||||
<style> |
|
||||||
body{ |
|
||||||
background-color: #555; |
|
||||||
color: #eeffee; |
|
||||||
} |
|
||||||
label{ |
|
||||||
display: block; |
|
||||||
} |
|
||||||
fieldset{ |
|
||||||
border-radius: 10px; |
|
||||||
display: inline; |
|
||||||
margin: 0 auto; |
|
||||||
} |
|
||||||
</style> |
|
@ -1,5 +0,0 @@ |
|||||||
<html> |
|
||||||
<body> |
|
||||||
Hallo {user}, dies ist die Index-Seite! |
|
||||||
</body> |
|
||||||
</html> |
|
@ -1,16 +0,0 @@ |
|||||||
<h1>Login</h1> |
|
||||||
|
|
||||||
<form action="login" method="POST"> |
|
||||||
<fieldset> |
|
||||||
<legend>Light OIDC Login</legend> |
|
||||||
<label> |
|
||||||
<input type="text" name="email" value="{email}" /> |
|
||||||
Email address |
|
||||||
</label> |
|
||||||
<label> |
|
||||||
<input type="password" name="password" value="{password}" /> |
|
||||||
Password |
|
||||||
</label> |
|
||||||
<button type="submit">Login</button> |
|
||||||
</fieldset> |
|
||||||
</form> |
|
@ -1,2 +0,0 @@ |
|||||||
title_login LightOIDC Login |
|
||||||
title_welcome Willkommen bei LightOIDC! |
|
@ -1,6 +0,0 @@ |
|||||||
<!DOCTYPE html> |
|
||||||
<html> |
|
||||||
{head} |
|
||||||
<body> |
|
||||||
{body} |
|
||||||
</html> |
|
@ -1 +0,0 @@ |
|||||||
Willkommen! |
|
@ -1,27 +0,0 @@ |
|||||||
/* © SRSoftware 2024 */ |
|
||||||
package de.srsoftware.oidc.server; |
|
||||||
|
|
||||||
import com.sun.net.httpserver.Headers; |
|
||||||
import com.sun.net.httpserver.HttpExchange; |
|
||||||
import de.srsoftware.oidc.api.PathHandler; |
|
||||||
import java.io.IOException; |
|
||||||
import java.util.Arrays; |
|
||||||
|
|
||||||
public class LanguageDirector extends PathHandler { |
|
||||||
private static final String DEFAULT_LANG = "de"; |
|
||||||
private final String path; |
|
||||||
|
|
||||||
public LanguageDirector(String pathTo) { |
|
||||||
path = pathTo; |
|
||||||
} |
|
||||||
|
|
||||||
@Override |
|
||||||
public void handle(HttpExchange t) throws IOException { |
|
||||||
Headers headers = t.getRequestHeaders(); |
|
||||||
String lang = headers.get("Accept-Language").stream().flatMap(s -> Arrays.stream(s.split(","))).findFirst().orElse(DEFAULT_LANG); |
|
||||||
|
|
||||||
t.getResponseHeaders().add("Location", String.join(lang, "/static/", "/de/index.html")); |
|
||||||
t.sendResponseHeaders(301, 0); |
|
||||||
t.getResponseBody().close(); |
|
||||||
} |
|
||||||
} |
|
@ -0,0 +1,23 @@ |
|||||||
|
/* © SRSoftware 2024 */ |
||||||
|
package de.srsoftware.oidc.web; |
||||||
|
|
||||||
|
import com.sun.net.httpserver.HttpExchange; |
||||||
|
import de.srsoftware.oidc.api.PathHandler; |
||||||
|
import java.io.IOException; |
||||||
|
|
||||||
|
public class Forward extends PathHandler { |
||||||
|
private final int CODE = 302; |
||||||
|
private final String toPath; |
||||||
|
|
||||||
|
public Forward(String toPath) { |
||||||
|
this.toPath = toPath; |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public void handle(HttpExchange ex) throws IOException { |
||||||
|
System.out.printf("Forwarding (%d) %s to %s…\n", CODE, ex.getRequestURI(), toPath); |
||||||
|
ex.getResponseHeaders().add("Location", toPath); |
||||||
|
ex.sendResponseHeaders(CODE, 0); |
||||||
|
ex.getResponseBody().close(); |
||||||
|
} |
||||||
|
} |
@ -0,0 +1 @@ |
|||||||
|
var api = "/api"; |
@ -1,9 +1,13 @@ |
|||||||
<html> |
<html> |
||||||
<head> |
<head> |
||||||
<title>{title}</title> |
<title>Light OIDC</title> |
||||||
<script src="lightoidc.js" /> |
<script src="config.js"></script> |
||||||
|
<script src="lightoidc.js"></script> |
||||||
|
<script> |
||||||
|
checkUser(); |
||||||
|
</script> |
||||||
</head> |
</head> |
||||||
<body> |
<body> |
||||||
{body} |
<h1>Welcome!</h1> |
||||||
</body> |
</body> |
||||||
</html> |
</html> |
@ -0,0 +1,25 @@ |
|||||||
|
const UNAUTHORIZED = 401; |
||||||
|
|
||||||
|
function handleCheckUser(response){ |
||||||
|
console.log(window.location.href); |
||||||
|
if (response.status == UNAUTHORIZED){ |
||||||
|
window.location.href = "login.html"; |
||||||
|
return; |
||||||
|
} |
||||||
|
} |
||||||
|
function checkUser(){ |
||||||
|
fetch(api+"/user") |
||||||
|
.then(handleCheckUser) |
||||||
|
.catch((err) => console.log(err)); |
||||||
|
} |
||||||
|
function submitForm(formId){ |
||||||
|
var data = Object.fromEntries(new FormData(document.getElementById(formId))); |
||||||
|
fetch(api+"/login",{ |
||||||
|
headers: { |
||||||
|
'login-username': data.user, |
||||||
|
'login-password': data.pass, // TODO: send via body?
|
||||||
|
Accept: 'application/json', |
||||||
|
'Content-Type': 'application/json' |
||||||
|
} |
||||||
|
}); |
||||||
|
} |
@ -0,0 +1,24 @@ |
|||||||
|
<html> |
||||||
|
<head> |
||||||
|
<title>Light OIDC</title> |
||||||
|
<script src="config.js"></script> |
||||||
|
<script src="lightoidc.js"></script> |
||||||
|
</head> |
||||||
|
<body> |
||||||
|
<h1>Login</h1> |
||||||
|
<form id="form"> |
||||||
|
<fieldset> |
||||||
|
<legend>User credentials</legend> |
||||||
|
<label> |
||||||
|
Username |
||||||
|
<input type="text" name="user" /> |
||||||
|
</label> |
||||||
|
<label> |
||||||
|
Password |
||||||
|
<input type="password" name="pass" /> |
||||||
|
</label> |
||||||
|
<button type="button" onClick="submitForm('form')">Login</button> |
||||||
|
</fieldset> |
||||||
|
</form> |
||||||
|
</body> |
||||||
|
</html> |
@ -1,6 +1,6 @@ |
|||||||
rootProject.name = 'LightOIDC' |
rootProject.name = 'LightOIDC' |
||||||
include 'de.srsoftware.oidc.api' |
include 'de.srsoftware.oidc.api' |
||||||
include 'de.srsoftware.oidc.light' |
include 'de.srsoftware.oidc.app' |
||||||
include 'de.srsoftware.oidc.server' |
|
||||||
include 'de.srsoftware.oidc.web' |
include 'de.srsoftware.oidc.web' |
||||||
|
include 'de.srsoftware.oidc.backend' |
||||||
|
|
||||||
|
Loading…
Reference in new issue