Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Issue #11560 - Implement EIP-4361 Sign-In With Ethereum #12188

Merged
merged 28 commits into from
Aug 26, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
436ca41
Issue #11560 - Implement EIP-4361 Sign-In With Ethereum
lachlan-roberts Jul 5, 2024
90e5919
PR #11883 - javadoc and code cleanup
lachlan-roberts Jul 5, 2024
ac5925a
PR #11883 - test fixes and cleanup
lachlan-roberts Jul 5, 2024
70e6192
PR #11883 - fixes to EthereumCredentials
lachlan-roberts Jul 5, 2024
614025a
Add openid and siwe documentation sections.
lachlan-roberts Jul 8, 2024
4006228
Merge remote-tracking branch 'origin/jetty-12.0.x' into jetty-12.0.x-…
lachlan-roberts Jul 12, 2024
225e89c
update version for jetty-siwe pom.xml
lachlan-roberts Jul 12, 2024
aa945d5
add jetty module for siwe
lachlan-roberts Jul 15, 2024
52c6c88
add siwe.mod, distribution tests and documentation
lachlan-roberts Jul 23, 2024
9ea7431
changes from review
lachlan-roberts Jul 23, 2024
32b7043
add javadoc for test classes
lachlan-roberts Jul 23, 2024
2f66835
PR #11883 - changes from review
lachlan-roberts Jul 25, 2024
44286fe
PR #11883 - changes from review
lachlan-roberts Jul 25, 2024
f1f1602
PR #11883 - changes from review
lachlan-roberts Jul 25, 2024
9581ef1
Merge remote-tracking branch 'origin/jetty-12.0.x' into jetty-12.0.x-…
lachlan-roberts Jul 25, 2024
37af005
Merge remote-tracking branch 'origin/jetty-12.0.x' into jetty-12.0.x-…
lachlan-roberts Aug 13, 2024
cc61f78
update poms to 12.0.13-SNAPSHOT
lachlan-roberts Aug 13, 2024
a525b70
Move SignInWithEthereumEmbeddedExample to code-examples in documentation
lachlan-roberts Aug 21, 2024
063e3fc
PR #11883 - fix build issue with poms
lachlan-roberts Aug 21, 2024
37aed0e
PR #11883 - remove experimental warning and fix to documentation
lachlan-roberts Aug 21, 2024
b07a8c0
Merge remote-tracking branch 'origin/jetty-12.0.x' into jetty-12.0.x-…
lachlan-roberts Aug 22, 2024
25cf822
Merge remote-tracking branch 'origin/jetty-12.0.x-SignInWithEthereum'…
lachlan-roberts Aug 22, 2024
8b21725
update supported versions in documentation to 12.1+
lachlan-roberts Aug 22, 2024
11509c2
update poms to 12.1.0-SNAPSHOT versions
lachlan-roberts Aug 22, 2024
b40a942
PR #12188 - move code to jetty-integrations/jetty-ethereum
lachlan-roberts Aug 23, 2024
28ae673
PR #12188 - rename siwe.mod to ethereum.mod
lachlan-roberts Aug 23, 2024
d56c962
Merge remote-tracking branch 'origin/jetty-12.1.x' into jetty-12.1.x-…
lachlan-roberts Aug 23, 2024
1b13c58
PR #12188 - fix parent of jetty-etherem pom.xml
lachlan-roberts Aug 23, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions documentation/jetty/modules/code/examples/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,10 @@
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-client</artifactId>
</dependency>
<dependency>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-ethereum</artifactId>
</dependency>
<dependency>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-infinispan-embedded-query</artifactId>
Expand Down Expand Up @@ -54,6 +58,10 @@
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-session</artifactId>
</dependency>
<dependency>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-slf4j-impl</artifactId>
</dependency>
<dependency>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-unixdomain-server</artifactId>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
//
// ========================================================================
// Copyright (c) 1995 Mort Bay Consulting Pty Ltd and others.
//
// This program and the accompanying materials are made available under the
// terms of the Eclipse Public License v. 2.0 which is available at
// https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
// which is available at https://www.apache.org/licenses/LICENSE-2.0.
//
// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
// ========================================================================
//

package org.eclipse.jetty.security.siwe.example;

import java.io.PrintWriter;
import java.nio.file.Paths;
import java.util.Objects;

import org.eclipse.jetty.http.HttpHeader;
import org.eclipse.jetty.io.Content;
import org.eclipse.jetty.security.AuthenticationState;
import org.eclipse.jetty.security.Constraint;
import org.eclipse.jetty.security.SecurityHandler;
import org.eclipse.jetty.security.siwe.EthereumAuthenticator;
import org.eclipse.jetty.server.Handler;
import org.eclipse.jetty.server.Request;
import org.eclipse.jetty.server.Response;
import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.server.ServerConnector;
import org.eclipse.jetty.server.handler.ContextHandler;
import org.eclipse.jetty.server.handler.ResourceHandler;
import org.eclipse.jetty.session.SessionHandler;
import org.eclipse.jetty.util.Callback;

public class SignInWithEthereum
{
public static SecurityHandler createSecurityHandler(Handler handler)
{
// tag::configureSecurityHandler[]
// This uses jetty-core, but you can configure a ConstraintSecurityHandler for use with EE10.
SecurityHandler.PathMapped securityHandler = new SecurityHandler.PathMapped();
securityHandler.setHandler(handler);
securityHandler.put("/*", Constraint.ANY_USER);

// Add the EthereumAuthenticator to the securityHandler.
EthereumAuthenticator authenticator = new EthereumAuthenticator();
securityHandler.setAuthenticator(authenticator);

// In embedded you can configure via EthereumAuthenticator APIs.
authenticator.setLoginPath("/login.html");

// Or you can configure with parameters on the SecurityHandler.
securityHandler.setParameter(EthereumAuthenticator.LOGIN_PATH_PARAM, "/login.html");
// end::configureSecurityHandler[]
return securityHandler;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
//
// ========================================================================
// Copyright (c) 1995 Mort Bay Consulting Pty Ltd and others.
//
// This program and the accompanying materials are made available under the
// terms of the Eclipse Public License v. 2.0 which is available at
// https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
// which is available at https://www.apache.org/licenses/LICENSE-2.0.
//
// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
// ========================================================================
//

package org.eclipse.jetty.docs.programming.security.siwe;

import java.io.PrintWriter;
import java.nio.file.Paths;
import java.util.Objects;

import org.eclipse.jetty.http.HttpHeader;
import org.eclipse.jetty.io.Content;
import org.eclipse.jetty.security.AuthenticationState;
import org.eclipse.jetty.security.Constraint;
import org.eclipse.jetty.security.SecurityHandler;
import org.eclipse.jetty.security.siwe.EthereumAuthenticator;
import org.eclipse.jetty.server.Handler;
import org.eclipse.jetty.server.Request;
import org.eclipse.jetty.server.Response;
import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.server.ServerConnector;
import org.eclipse.jetty.server.handler.ContextHandler;
import org.eclipse.jetty.server.handler.ResourceHandler;
import org.eclipse.jetty.session.SessionHandler;
import org.eclipse.jetty.util.Callback;

public class SignInWithEthereumEmbeddedExample
{
public static void main(String[] args) throws Exception
{
Server server = new Server();
ServerConnector connector = new ServerConnector(server);
connector.setPort(8080);
server.addConnector(connector);

String resourcePath = Paths.get(Objects.requireNonNull(SignInWithEthereumEmbeddedExample.class.getClassLoader().getResource("")).toURI())
.resolve("../../src/main/resources/")
.normalize().toString();
System.err.println(resourcePath);
ResourceHandler resourceHandler = new ResourceHandler();
resourceHandler.setDirAllowed(false);
resourceHandler.setBaseResourceAsString(resourcePath);

Handler.Abstract handler = new Handler.Wrapper(resourceHandler)
{
@Override
public boolean handle(Request request, Response response, Callback callback) throws Exception
{
String pathInContext = Request.getPathInContext(request);
if ("/login.html".equals(pathInContext))
{
return super.handle(request, response, callback);
}
else if ("/logout".equals(pathInContext))
{
AuthenticationState.logout(request, response);
Response.sendRedirect(request, response, callback, "/");
callback.succeeded();
return true;
}

AuthenticationState authState = Objects.requireNonNull(AuthenticationState.getAuthenticationState(request));
response.getHeaders().add(HttpHeader.CONTENT_TYPE, "text/html");
try (PrintWriter writer = new PrintWriter(Content.Sink.asOutputStream(response)))
{
writer.write("UserPrincipal: " + authState.getUserPrincipal());
writer.write("<br><a href=\"/logout\">Logout</a>");
}
callback.succeeded();
return true;
}
};

SecurityHandler securityHandler = createSecurityHandler(handler);
SessionHandler sessionHandler = new SessionHandler();
sessionHandler.setHandler(securityHandler);

ContextHandler contextHandler = new ContextHandler();
contextHandler.setContextPath("/");
contextHandler.setHandler(sessionHandler);

server.setHandler(contextHandler);
server.start();
server.join();
}

public static SecurityHandler createSecurityHandler(Handler handler)
{
// tag::configureSecurityHandler[]
// This uses jetty-core, but you can configure a ConstraintSecurityHandler for use with EE10.
SecurityHandler.PathMapped securityHandler = new SecurityHandler.PathMapped();
securityHandler.setHandler(handler);
securityHandler.put("/*", Constraint.ANY_USER);

// Add the EthereumAuthenticator to the securityHandler.
EthereumAuthenticator authenticator = new EthereumAuthenticator();
securityHandler.setAuthenticator(authenticator);

// In embedded you can configure via EthereumAuthenticator APIs.
authenticator.setLoginPath("/login.html");

// Or you can configure with parameters on the SecurityHandler.
securityHandler.setParameter(EthereumAuthenticator.LOGIN_PATH_PARAM, "/login.html");
// end::configureSecurityHandler[]

return securityHandler;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Sign-In with Ethereum</title>
<script src="https://cdn.jsdelivr.net/npm/web3@1.6.1/dist/web3.min.js"></script>
</head>
<body>
<h4>Sign-In with Ethereum</h4>
<button id="siwe">Sign-In with Ethereum</button>
<form id="loginForm" action="/auth/login" method="POST" style="display: none;">
<input type="hidden" id="signatureField" name="signature">
<input type="hidden" id="messageField" name="message">
</form>
<p class="alert" style="display: none;">Result: <span id="siweResult"></span></p>

<script>
let provider = window.ethereum;
let accounts;

if (!provider) {
document.getElementById('siweResult').innerText = 'MetaMask is not installed. Please install MetaMask to use this feature.';
} else {
document.getElementById('siwe').addEventListener('click', async () => {
try {
// Request account access if needed
accounts = await provider.request({ method: 'eth_requestAccounts' });
const domain = window.location.host;
const from = accounts[0];

// Fetch nonce from the server
const nonceResponse = await fetch('/auth/nonce');
const nonceData = await nonceResponse.json();
const nonce = nonceData.nonce;

const siweMessage = `${domain} wants you to sign in with your Ethereum account:\n${from}\n\nI accept the MetaMask Terms of Service: https://community.metamask.io/tos\n\nURI: https://${domain}\nVersion: 1\nChain ID: 1\nNonce: ${nonce}\nIssued At: ${new Date().toISOString()}`;
const signature = await provider.request({
method: 'personal_sign',
params: [siweMessage, from]
});
console.log("signature: " + signature)
console.log("nonce: " + nonce)
console.log("length: " + length)

document.getElementById('signatureField').value = signature;
document.getElementById('messageField').value = siweMessage;
document.getElementById('loginForm').submit();
} catch (error) {
console.error('Error during login:', error);
document.getElementById('siweResult').innerText = `Error: ${error.message}`;
document.getElementById('siweResult').parentElement.style.display = 'block';
}
});
}
</script>
</body>
</html>
2 changes: 2 additions & 0 deletions documentation/jetty/modules/programming-guide/nav.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,8 @@
** xref:troubleshooting/state-tracking.adoc[]
** xref:troubleshooting/component-dump.adoc[]
** xref:troubleshooting/debugging.adoc[]
* Jetty Security
** xref:security/siwe-support.adoc[]
* Migration Guides
** xref:migration/94-to-10.adoc[]
** xref:migration/11-to-12.adoc[]
Expand Down
Loading
Loading