Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
16 changes: 14 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ More information about the Web eID project is available on the project [website]

# Quickstart

Complete the steps below to add support for secure authentication with eID cards to your Java web application back end. Instructions for the front end are available [here](https://github.com/web-eid/web-eid.js).
Complete the steps below to add support for secure authentication with eID cards to your Java web application back end. Instructions for the front end are available [here](https://github.com/web-eid/web-eid.js). If your application already uses Web eID and you only need to add the mobile flow, see [Adding Web eID for Mobile support to an existing integration](#adding-web-eid-for-mobile-support-to-an-existing-integration).

A Java web application that uses Maven or Gradle to manage packages is needed for running this quickstart. Examples are for Maven, but they are straightforward to translate to Gradle.

Expand Down Expand Up @@ -183,7 +183,7 @@ public final class WebEidChallengeNonceFilter extends OncePerRequestFilter {
}
```

The `WebEidMobileAuthInitFilter` handles `/auth/mobile/init` requests for authentication flows using **Web eID token format v1.1**. It generates a challenge nonce and returns a deep link URI that embeds both the challenge nonce and the authentication endpoint required for initiating the v1.1 flow.
The `WebEidMobileAuthInitFilter` handles `/auth/mobile/init` requests for mobile authentication. It generates a challenge nonce and returns a deep link URI containing the challenge nonce, the login page URL and an optional request for a signing certificate. The response uses token format `web-eid:1.1` when a signing certificate is requested, or `web-eid:1.0` for authentication only.
See the full implementation [here](example/src/main/java/eu/webeid/example/security/WebEidMobileAuthInitFilter.java).

```java
Expand Down Expand Up @@ -252,9 +252,21 @@ try {
...
```

## Adding Web eID for Mobile support to an existing integration

Reuse your existing challenge nonce generator and store, trusted CA configuration, token validation and authorization logic. The mobile flow adds an App Link/Universal Link that opens the RIA DigiDoc app and a login page that receives the response in its URL fragment and posts the token to your back end. Authentication-only responses use `web-eid:1.0`; requesting a signing certificate with `getSigningCertificate=true` requires a validator that supports `web-eid:1.1`. The validator configuration stays the same.

1. Add `POST /auth/mobile/init` to generate and store a challenge nonce and return `authUri`: `https://id.eesti.ee/auth#<payload>`, where the payload is Base64-encoded JSON containing `challenge`, `loginUri` and optionally `getSigningCertificate` ([init filter](example/src/main/java/eu/webeid/example/security/WebEidMobileAuthInitFilter.java)). Set `web-eid-mobile.base-request-uri` to `https://id.eesti.ee` for the RIA DigiDoc app; the example defaults to the development scheme `web-eid-mobile://`. Configure `web-eid-mobile.request-signing-cert` as needed and enable `web-eid-mobile.enabled` if previously disabled.
2. Serve `GET /auth/mobile/login` at an HTTPS `loginUri` on the validator's configured `web-eid-auth-token.validation.local-origin`. Its script must decode the response, handle errors and post `authToken` to the existing `POST /auth/login` endpoint ([login page](example/src/main/resources/templates/webeid-login.html), [payload parser](example/src/main/resources/static/js/payload.js)). Retrieve and consume the session's unexpired challenge nonce, validate the token, apply your authorization checks and establish the authenticated session as before.
3. Use `Secure`, `HttpOnly`, `SameSite=Lax` for the pre-authentication session cookie so it accompanies the return from the app. Keep CSRF protection on POST endpoints and protect the login page against XSS. Callback fragments are untrusted input; the CSRF token alone does not authenticate them. See the architecture document's [security assumptions](https://github.com/web-eid/web-eid-for-mobile-architecture-doc#security-assumptions).
4. Add a mobile login button that calls the init endpoint and opens the returned `authUri` ([front end](example/src/main/resources/templates/index.html)). Keep the existing desktop login control.

Optional mobile signing is demonstrated by [SigningController](example/src/main/java/eu/webeid/example/web/rest/SigningController.java) and [MobileSigningService](example/src/main/java/eu/webeid/example/service/MobileSigningService.java). A validated signing certificate returned during authentication can be stored with its supported algorithms to skip the separate certificate request. Check that the signing certificate belongs to the authenticated user before preparing the data to sign.

# Table of contents

- [Quickstart](#quickstart)
- [Adding Web eID for Mobile support to an existing integration](#adding-web-eid-for-mobile-support-to-an-existing-integration)
- [Introduction](#introduction)
- [Authentication token format](#authentication-token-format)
- [Authentication token validation](#authentication-token-validation)
Expand Down
9 changes: 9 additions & 0 deletions example/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,7 @@ When the application has started, open the _ngrok_ HTTPS URL in your preferred w
+ [Overview of the source code](#overview-of-the-source-code)
+ [Configuration](#configuration)
+ [Integration with Web eID components](#integration-with-web-eid-components)
+ [Adding Web eID for Mobile support to an existing integration](#adding-web-eid-for-mobile-support-to-an-existing-integration)
+ [Integration with DigiDoc4j components](#integration-with-digidoc4j-components)
- [Using the Certificates' *Authority Information Access* (AIA) extension in DigiDoc4j](#using-the-certificates-authority-information-access-aia-extension-in-digidoc4j)
- [Using DigiDoc4j in test mode with the `dev` profile](#using-digidoc4j-in-test-mode-with-the-dev-profile)
Expand Down Expand Up @@ -158,6 +159,14 @@ Detailed overview of Java code changes required for integrating Web eID authenti

A similar overview of JavaScript and HTML code changes required for authentication and digital signing with Web eID is available in the [web-eid.js library README](https://github.com/web-eid/web-eid.js/blob/main/README.md). The corresponding JavaScript and HTML code is in the `src/resources/{static,templates}` directories.

### Adding Web eID for Mobile support to an existing integration

To add mobile authentication to an existing integration, follow the [library migration guide](../README.md#adding-web-eid-for-mobile-support-to-an-existing-integration). This example adds `POST /auth/mobile/init` through `WebEidMobileAuthInitFilter` and `GET /auth/mobile/login` through `WebEidLoginPageGeneratingFilter`, using `templates/webeid-login.html` and `static/js/payload.js`. Both login flows submit to `POST /auth/login` and share `WebEidAuthenticationProvider`.

Configure `web-eid-mobile.base-request-uri`, `web-eid-mobile.request-signing-cert` and `web-eid-auth-token.validation.local-origin` in `application-{dev,prod}.yaml`. Set the base request URI to `https://id.eesti.ee` for the RIA DigiDoc app; both profiles currently use `web-eid-mobile://` for development. `web-eid-mobile.enabled` selects the mobile-enabled security filter chain in `ApplicationConfiguration`. The mobile button is in `templates/index.html`; `SameSiteCookieConfiguration` sets `SameSite=Lax`, and `application.yaml` enables forwarded HTTPS detection behind a reverse proxy. Spring Security CSRF protection remains enabled.

For optional mobile signing, see `SigningController`, `MobileSigningService` and `templates/webeid-callback.html`. `WebEidAuthentication` stores a signing certificate from the validated token when requested; `SigningService.prepareContainer()` checks its subject ID against the authenticated user's ID.

### Integration with DigiDoc4j components

Java code examples that show how to create and sign data containers that hold signed file objects and digital signatures is available in the [DigiDoc4j wiki](https://github.com/open-eid/digidoc4j/wiki/Examples-of-using-it). Further information and links to the API documentation is available in the project [README](https://github.com/open-eid/digidoc4j/blob/master/README.md). The corresponding Java code is in the `src/main/java/eu/webeid/example/{service,web/rest}` directories.
Expand Down
11 changes: 11 additions & 0 deletions example/src/test/java/eu/webeid/example/WebApplicationTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
import eu.webeid.security.authtoken.WebEidAuthToken;
import eu.webeid.security.challenge.ChallengeNonce;
import eu.webeid.security.util.DateAndTime;
import eu.webeid.security.validator.certvalidators.SubjectCertificateNotRevokedValidator;
import mockit.Mock;
import mockit.MockUp;
import org.digidoc4j.impl.asic.AsicSignatureFinalizer;
Expand All @@ -49,6 +50,7 @@
import org.springframework.test.web.servlet.setup.MockMvcBuilders;
import org.springframework.web.context.WebApplicationContext;

import java.security.cert.X509Certificate;
import java.util.stream.Stream;

import static eu.webeid.example.testutil.ObjectMother.VALID_AUTH_TOKEN;
Expand Down Expand Up @@ -101,6 +103,15 @@ public void validateOcspResponse(XadesSignature xadesSignature) {
}
};

new MockUp<SubjectCertificateNotRevokedValidator>() {
@Mock
public void validateCertificateNotRevoked(X509Certificate subjectCertificate) {
// Do not call real OCSP service in tests. The test certificates have expired, so the
// validation clock is mocked to a date in the past, but OCSP responses are always
// current, which makes the OCSP response time and responder certificate checks fail.
}
};

MockHttpSession session = new MockHttpSession();
session.setAttribute("challenge-nonce", new ChallengeNonce(ObjectMother.VALID_CHALLENGE_NONCE, DateAndTime.utcNow().plusMinutes(1)));

Expand Down
Empty file.
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@
/**
* Validators perform the actual user certificate validation actions.
* <p>
* They are used by AuthTokenValidatorImpl and are not part of the public API.
* They are used by AuthTokenVersionValidatorFactory and are not part of the public API.
*/
@FunctionalInterface
public interface SubjectCertificateValidator {
Expand Down
Loading