Skip to content

About

Web eID authentication token validation library for Java

Resources

Contributing

Stars

3 stars

Watchers

9 watching

Forks

 
 

Latest commit

 

History

246 Commits

Folders and files

Repository files navigation

web-eid-authtoken-validation-java

European Regional Development Fund

web-eid-authtoken-validation-java is a Java library for issuing challenge nonces and validating Web eID authentication tokens during secure authentication with electronic ID (eID) smart cards in web applications.

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. 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.

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.

In the following example we are using the Spring Framework, but the examples can be easily ported to other Java web application frameworks.

Full example project using the validation library in spring-boot

example/README.md

1. Add the library to your project

Add the following lines to Maven pom.xml to include the Web eID authentication token validation library in your project:

<dependencies>
    <dependency>
        <groupId>eu.webeid.security</groupId>
        <artifactId>authtoken-validation</artifactId>
        <version>${webeid.version}</version>
    </dependency>
</dependencies>

<repositories>
    <repository>
        <id>gitlab</id>
        <url>https://gitlab.com/api/v4/projects/19948337/packages/maven</url>
    </repository>
</repositories>

2. Configure the challenge nonce store

The validation library needs a store for saving the issued challenge nonces. As it must be guaranteed that the authentication token is received from the same browser to which the corresponding challenge nonce was issued, using a session-backed challenge nonce store is the most natural choice.

Implement the session-backed challenge nonce store as follows:

import org.springframework.beans.factory.ObjectFactory;
import eu.webeid.security.challenge.ChallengeNonce;
import eu.webeid.security.challenge.ChallengeNonceStore;
import jakarta.servlet.http.HttpSession;

public class SessionBackedChallengeNonceStore implements ChallengeNonceStore {

    private static final String CHALLENGE_NONCE_KEY = "challenge-nonce";
    final ObjectFactory<HttpSession> httpSessionFactory;

    public SessionBackedChallengeNonceStore(ObjectFactory<HttpSession> httpSessionFactory) {
        this.httpSessionFactory = httpSessionFactory;
    }

    @Override
    public void put(ChallengeNonce challengeNonce) {
        currentSession().setAttribute(CHALLENGE_NONCE_KEY, challengeNonce);
    }

    @Override
    public ChallengeNonce getAndRemoveImpl() {
        final ChallengeNonce challengeNonce = (ChallengeNonce) currentSession().getAttribute(CHALLENGE_NONCE_KEY);
        currentSession().removeAttribute(CHALLENGE_NONCE_KEY);
        return challengeNonce;
    }

    private HttpSession currentSession() {
        return httpSessionFactory.getObject();
    }
}

3. Configure the challenge nonce generator

The validation library needs to generate authentication challenge nonces and store them for later validation in the challenge nonce store. Overview of challenge nonce usage is provided in the Web eID system architecture document. The challenge nonce generator will be used in the filter that issues challenges; it is thread-safe and should be scoped as a singleton.

Configure the challenge nonce generator as follows:

import eu.webeid.security.challenge.ChallengeNonceGenerator;
import eu.webeid.security.challenge.ChallengeNonceGeneratorBuilder;
import eu.webeid.security.challenge.ChallengeNonceStore;

...
    public ChallengeNonceGenerator generator(ChallengeNonceStore challengeNonceStore) {
        return new ChallengeNonceGeneratorBuilder()
                .withChallengeNonceStore(challengeNonceStore)
                .build();
    }
...

4. Add trusted certificate authority certificates

You must explicitly specify which intermediate certificate authorities (CAs) are trusted to issue the eID authentication and OCSP responder certificates. CA certificates can be loaded from either the truststore file, resources or any stream source. We use the CertificateLoader helper class to load CA certificates from resources here, but consider loading the truststore file (see loadTrustedCACertificatesFromTrustStore) instead.

First, copy the trusted certificates, for example ESTEID2018.cer, to resources/cacerts/, then load the certificates as follows:

import java.security.cert.X509Certificate;
import eu.webeid.security.certificate.CertificateLoader;

...
    private X509Certificate[] trustedIntermediateCACertificates() {
         return CertificateLoader.loadCertificatesFromResources("cacerts/ESTEID2018.cer");
    }
...

5. Configure the authentication token validator

Once the prerequisites have been met, the authentication token validator itself can be configured. The mandatory parameters are the website origin (the URL serving the web application, see section Basic usage below) and trusted certificate authorities. The authentication token validator will be used in the login processing component of your web application authentication framework; it is thread-safe and should be scoped as a singleton.

import java.net.URI;
import eu.webeid.security.validator.AuthTokenValidator;
import eu.webeid.security.validator.AuthTokenValidatorBuilder;

...
    public AuthTokenValidator tokenValidator() throws JceException {
        return new AuthTokenValidatorBuilder()
                .withSiteOrigin(URI.create("https://example.org"))
                .withTrustedCertificateAuthorities(trustedIntermediateCACertificates())
                .build();
    }
...

The site origin configured with withSiteOrigin() must match the origin string signed by the Web eID application. Use the ASCII serialization of the origin as specified by the Web eID architecture document. For internationalized domain names, configure the Punycode form, for example https://xn--pike-loa.ee for https://päike.ee.

6. Add a filter for issuing challenge nonces

Request Filters that issue challenge nonces for regular Web eID and Web eID for Mobile authentication flows are required for authentication. The filters must support POST requests.

The WebEidChallengeNonceFilter handles /auth/challenge requests and issues a new nonce for regular Web eID authentication flow. See the full implementation here.

public final class WebEidChallengeNonceFilter extends OncePerRequestFilter {
    private static final ObjectWriter OBJECT_WRITER = new ObjectMapper().writer();
    private final RequestMatcher requestMatcher;
    private final ChallengeNonceGenerator nonceGenerator;

    public WebEidChallengeNonceFilter(String path, ChallengeNonceGenerator nonceGenerator) {
        this.requestMatcher = PathPatternRequestMatcher.withDefaults().matcher(HttpMethod.POST, path);
        this.nonceGenerator = nonceGenerator;
    }

    @Override
    protected void doFilterInternal(
        @NonNull HttpServletRequest request,
        @NonNull HttpServletResponse response,
        @NonNull FilterChain chain
    ) throws ServletException, IOException {
        if (!requestMatcher.matches(request)) {
            chain.doFilter(request, response);
            return;
        }

        var dto = new ChallengeDTO(nonceGenerator.generateAndStoreNonce().getBase64EncodedNonce());

        response.setContentType(MediaType.APPLICATION_JSON_VALUE);
        OBJECT_WRITER.writeValue(response.getWriter(), dto);
    }

    public record ChallengeDTO(String nonce) {}
}

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.

@Override
protected void doFilterInternal(@NonNull HttpServletRequest request,
                                @NonNull HttpServletResponse response,
                                @NonNull FilterChain chain) throws IOException, ServletException {
    if (!requestMatcher.matches(request)) {
        chain.doFilter(request, response);
        return;
    }

    var challenge = nonceGenerator.generateAndStoreNonce();

    String loginUri = UriComponentsBuilder
        .fromUriString(webEidAuthTokenProperties.validation().localOrigin())
        .path(mobileLoginPath)
        .build()
        .toUriString();

    String payloadJson = OBJECT_WRITER.writeValueAsString(
        new AuthPayload(challenge.getBase64EncodedNonce(), loginUri,
            webEidMobileProperties.requestSigningCert() ? Boolean.TRUE : null)
    );
    String encoded = Base64.getEncoder().encodeToString(payloadJson.getBytes(StandardCharsets.UTF_8));
    String authUri = getAuthUri(encoded);

    response.setContentType(MediaType.APPLICATION_JSON_VALUE);
    OBJECT_WRITER.writeValue(response.getWriter(), new AuthUri(authUri));
}

Both filters are registered in the Spring Security filter chain in ApplicationConfiguration. See the full implementation here:

http
    .addFilterBefore(new WebEidMobileAuthInitFilter("/auth/mobile/init", "/auth/mobile/login", challengeNonceGenerator,
                     webEidMobileProperties, webEidAuthTokenProperties), UsernamePasswordAuthenticationFilter.class)
    .addFilterBefore(new WebEidChallengeNonceFilter("/auth/challenge", challengeNonceGenerator),
        UsernamePasswordAuthenticationFilter.class);

Also, see general guidelines for implementing secure authentication services here.

7. Implement authentication

Authentication consists of calling the validate() method of the authentication token validator. The internal implementation of the validation process is described in more detail below and in the Web eID system architecture document.

When using Spring Security with standard cookie-based authentication,

  • implement a custom authentication provider that uses the authentication token validator for authentication as shown here,
  • implement an AJAX authentication processing filter that extracts the authentication token and passes it to the authentication manager as shown here,
  • configure the authentication provider and authentication processing filter in the application configuration as shown here.

The gist of the validation is in the authenticate() method of the authentication provider:

try {
    final String nonce = challengeNonceStore.getAndRemove().getBase64EncodedNonce();
    final X509Certificate userCertificate = tokenValidator.validate(authToken, nonce);
    final var signingCertificate = requireSigningCert && !CollectionUtils.isEmpty(authToken.getUnverifiedSigningCertificates())
        ? authToken.getUnverifiedSigningCertificates().getFirst() // NOTE: Handling multiple signing certificates is out of scope of this example.
        : null;
            return WebEidAuthentication.fromCertificate(userCertificate, signingCertificate, authorities);
} catch (AuthTokenException e) {
  ...

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). 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, payload parser). 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.
  4. Add a mobile login button that calls the init endpoint and opens the returned authUri (front end). Keep the existing desktop login control.

Optional mobile signing is demonstrated by SigningController and MobileSigningService. 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

Introduction

The Web eID authentication token validation library for Java contains the implementation of the Web eID authentication token validation process in its entirety to ensure that the authentication token sent by the Web eID browser extension or mobile application contains valid, consistent data that has not been modified by a third party. It also implements secure challenge nonce generation as required by the Web eID authentication protocol. It is easy to configure and integrate into your authentication service.

The authentication protocol, authentication token format, validation requirements and challenge nonce usage is described in more detail in the Web eID system architecture document.

Authentication token format

In the following,

  • origin is defined as the website origin, the URL serving the web application,
  • challenge nonce (or challenge) is defined as a cryptographic nonce, a large random number that can be used only once, with at least 256 bits of entropy.

A Web eID authentication token in web-eid:1.0 format is a JSON data structure that looks like the following example:

{
  "unverifiedCertificate": "MIIFozCCA4ugAwIBAgIQHFpdK-zCQsFW4...",
  "algorithm": "RS256",
  "signature": "HBjNXIaUskXbfhzYQHvwjKDUWfNu4yxXZha...",
  "format": "web-eid:1.0",
  "appVersion": "https://web-eid.eu/web-eid-app/releases/v2.0.0"
}

It contains the following fields:

  • unverifiedCertificate: the base64-encoded DER-encoded authentication certificate of the eID user; the public key contained in this certificate should be used to verify the signature; the certificate cannot be trusted as it is received from client side and the client can submit a malicious certificate; to establish trust, it must be verified that the certificate is signed by a trusted certificate authority,

  • algorithm: the signature algorithm used to produce the signature; the allowed values are the algorithms specified in JWA RFC sections 3.3, 3.4 and 3.5:

      "ES256", "ES384", "ES512", // ECDSA
      "PS256", "PS384", "PS512", // RSASSA-PSS
      "RS256", "RS384", "RS512"  // RSASSA-PKCS1-v1_5
    
  • signature: the base64-encoded signature of the token (see the description below),

  • format: the type identifier and version of the token format separated by a colon character ':', web-eid:1.0 or web-eid:1.1 as of now; the version number consists of the major and minor number separated by a dot, major version changes are incompatible with previous versions, minor version changes are backwards-compatible within the given major version,

  • appVersion: the URL identifying the name and version of the application that issued the token; informative purpose, can be used to identify the affected application in case of faulty tokens.

The value that is signed by the user’s authentication private key and included in the signature field is hash(origin)+hash(challenge). The hash function is used before concatenation to ensure field separation as the hash of a value is guaranteed to have a fixed length. Otherwise the origin example.com with challenge nonce .eu1234 and another origin example.com.eu with challenge nonce 1234 would result in the same value after concatenation. The hash function hash is the same hash function that is used in the signature algorithm, for example SHA256 in case of RS256.

A Web eID authentication token in web-eid:1.1 format is a JSON data structure that looks like the following example:

{
  "unverifiedCertificate": "MIIFozCCA4ugAwIBAgIQHFpdK-zCQsFW4...",
  "algorithm": "RS256",
  "signature": "HBjNXIaUskXbfhzYQHvwjKDUWfNu4yxXZha...",
  "unverifiedSigningCertificates": [
    {
      "certificate": "MIIFikACB3ugAwASAgIHHFrtdZ-zeQsas1...",
      "supportedSignatureAlgorithms": [
        {
          "cryptoAlgorithm": "ECC",
          "hashFunction": "SHA-384",
          "paddingScheme": "NONE"
        }
      ]
    }
  ],
  "format": "web-eid:1.1",
  "appVersion": "https://web-eid.eu/web-eid-app/releases/v2.0.0"
}

It contains the following fields:

  • unverifiedSigningCertificates: an array of objects containing signing certificate information.

Each object inside unverifiedSigningCertificates contains:

  • certificate: base64-encoded DER-encoded signing certificate,

  • supportedSignatureAlgorithms: list of supported algorithms in the following format:

    • cryptoAlgorithm: the cryptographic algorithm used for the key,

    • hashFunction: the hashing algorithm used,

    • paddingScheme: the padding scheme used (if applicable).

Allowed values are:

cryptoAlgorithm: "ECC", "RSA"

hashFunction:
  "SHA-224", "SHA-256", "SHA-384", "SHA-512",
  "SHA3-224", "SHA3-256", "SHA3-384", "SHA3-512"

paddingScheme: "NONE", "PKCS1.5", "PSS"

Authentication token validation

The authentication token validation process consists of the following stages:

  • First, user certificate validation: the validator parses the token and extracts the user certificate from the unverifiedCertificate field. Then it checks the certificate expiration, purpose and policies. Next it checks that the certificate is signed by a trusted CA and checks the certificate status with OCSP.
  • Second, token signature validation: the validator validates that the token signature was created using the provided user certificate by reconstructing the signed data hash(origin)+hash(challenge) and using the public key from the certificate to verify the signature in the signature field. If the signature verification succeeds, then the origin and challenge nonce have been implicitly and correctly verified without the need to implement any additional security checks.
  • Additional validation for Web eID authentication tokens (format v1.1): the token must contain the unverifiedSigningCertificates field with at least one signing certificate entry. Each entry's supportedSignatureAlgorithms are validated against the set of allowed cryptographic algorithms, hash functions, and padding schemes. For each signing certificate, the following checks are performed:
    • The subject must match the subject of the authentication certificate, ensuring both certificates belong to the same user.
    • The issuing authority must match that of the authentication certificate, verified via the Authority Key Identifier (AKI) extension.
    • The certificate must be within its validity period.
    • The certificate must contain the non-repudiation key usage bit required for digital signatures.
    • The certificate chain must validate against the configured trusted certificate authorities.

The website back end must look up the challenge nonce from its local store using an identifier specific to the browser session, to guarantee that the authentication token was received from the same browser to which the corresponding challenge nonce was issued. The website back end must guarantee that the challenge nonce lifetime is limited and that its expiration is checked, and that it can be used only once by removing it from the store during validation.

Basic usage

As described in section 5. Configure the authentication token validator, the mandatory authentication token validator configuration parameters are the website origin and trusted certificate authorities.

Origin must be the URL serving the web application. Origin URL must be in the form of "https://" <hostname> [ ":" <port> ] as defined in MDN and not contain path or query components. Note that the origin URL must not end with a slash /. The configured origin must use the ASCII serialization that is signed by the Web eID application. For internationalized domain names, use the Punycode form, for example https://xn--pike-loa.ee instead of https://päike.ee.

The trusted certificate authority certificates are used to validate that the user certificate from the authentication token and the OCSP responder certificate is signed by a trusted certificate authority. Intermediate CA certificates must be used instead of the root CA certificates so that revoked CA certificates can be removed. Trusted certificate authority certificates configuration is described in more detail in section 4. Add trusted certificate authority certificates.

Before validation, the previously issued challenge nonce must be looked up from the store using an identifier specific to the browser session. The challenge nonce must be passed to the validate() method in the corresponding parameter. Setting up the challenge nonce store is described in more detail in section 2. Configure the challenge nonce store.

The authentication token validator configuration and construction is described in more detail in section 5. Configure the authentication token validator. Once the validator object has been constructed, it can be used for validating authentication tokens as follows:

String challengeNonce = challengeNonceStore.getAndRemove().getBase64EncodedNonce();
WebEidAuthToken token = tokenValidator.parse(tokenString);
X509Certificate userCertificate = tokenValidator.validate(token, challengeNonce);

The validate() method returns the validated user certificate object if validation is successful or throws an exception as described in section Possible validation errors below if validation fails. The CertificateData and TitleCase classes can be used for extracting user information from the user certificate object:

import eu.webeid.security.certificate.CertificateData;
import static eu.webeid.security.util.Strings.toTitleCase;

...
    
CertificateData.getSubjectCN(userCertificate).orElseThrow(); // "JÕEORG\\,JAAK-KRISTJAN\\,38001085718"
CertificateData.getSubjectIdCode(userCertificate).orElseThrow(); // "PNOEE-38001085718"
CertificateData.getSubjectCountryCode(userCertificate).orElseThrow(); // "EE"

toTitleCase(CertificateData.getSubjectGivenName(userCertificate).orElseThrow()); // "Jaak-Kristjan"
toTitleCase(CertificateData.getSubjectSurname(userCertificate).orElseThrow()); // "Jõeorg"

Extended configuration

The following additional configuration options are available in AuthTokenValidatorBuilder:

  • withoutUserCertificateRevocationCheckWithOcsp() – turns off user certificate revocation check with OCSP. OCSP check is enabled by default and the OCSP responder access location URL is extracted from the user certificate AIA extension unless a designated OCSP service is activated.
  • withDesignatedOcspServiceConfiguration(DesignatedOcspServiceConfiguration serviceConfiguration) – activates the provided designated OCSP responder service configuration for user certificate revocation check with OCSP. The designated service is only used for checking the status of the certificates whose issuers are supported by the service, for other certificates the default AIA extension service access location will be used. See configuration examples in testutil.OcspServiceMaker.getDesignatedOcspServiceConfiguration().
  • withOcspClient(OcspClient ocspClient) - uses the provided OCSP client instance during user certificate revocation check with OCSP. The provided client instance must be thread-safe. This gives the possibility to configure the request timeouts, proxies etc of the HttpClient instance or provide an implementation that uses an altogether different HTTP client. See examples in OcspClientOverrideTest.
  • withOcspRequestTimeout(Duration ocspRequestTimeout) – sets both the connection and response timeout of user certificate revocation check OCSP requests. Default is 5 seconds.
  • withDisallowedCertificatePolicies(ASN1ObjectIdentifier... policies) – adds the given policies to the list of disallowed user certificate policies. In order for the user certificate to be considered valid, it must not contain any policies present in this list. Contains the Estonian Mobile-ID policies by default as it must not be possible to authenticate with a Mobile-ID certificate when an eID smart card is expected.
  • withNonceDisabledOcspUrls(URI... urls) – adds the given URLs to the list of OCSP responder access location URLs for which the nonce protocol extension will be disabled. Some OCSP responders don't support the nonce extension.
  • withAllowedOcspResponseTimeSkew(Duration allowedTimeSkew) – sets the allowed time skew for OCSP response's thisUpdate and nextUpdate times to allow discrepancies between the system clock and the OCSP responder's clock or revocation updates that are not published in real time. The default allowed time skew is 15 minutes. The relatively long default is specifically chosen to account for one particular OCSP responder that used CRLs for authoritative revocation info, these CRLs were updated every 15 minutes.
  • withMaxOcspResponseThisUpdateAge(Duration maxThisUpdateAge) – sets the maximum age for the OCSP response's thisUpdate time before it is considered too old to rely on. The default maximum age is 2 minutes.

Extended configuration example:

AuthTokenValidator validator = new AuthTokenValidatorBuilder()
    .withSiteOrigin(URI.create("https://example.org"))
    .withTrustedCertificateAuthorities(trustedCertificateAuthorities())
    .withoutUserCertificateRevocationCheckWithOcsp()
    .withDisallowedCertificatePolicies(new ASN1ObjectIdentifier("1.2.3"))
    .withNonceDisabledOcspUrls(URI.create("http://aia.example.org/cert"))
    .withAllowedOcspResponseTimeSkew(Duration.ofMinutes(10))
    .withMaxOcspResponseThisUpdateAge(Duration.ofMinutes(5))
    .build();

Certificates' Authority Information Access (AIA) extension

Unless a designated OCSP responder service is in use, it is required that the AIA extension that contains the certificate’s OCSP responder access location is present in the user certificate. The AIA OCSP URL will be used to check the certificate revocation status with OCSP.

Note that there may be limitations to using AIA URLs as the services behind these URLs provide different security and SLA guarantees than dedicated OCSP responder services. In case you need a SLA guarantee, use a designated OCSP responder service.

Possible validation errors

The validate() method of AuthTokenValidator returns the validated user certificate object if validation is successful or throws an exception if validation fails. All exceptions that can occur during validation derive from AuthTokenException, the list of available exceptions is available here. Each exception file contains a documentation comment that describes under which conditions the exception is thrown.

Stateful and stateless authentication

In the code examples above we use the classical stateful Spring Security session cookie-based authentication mechanism, where a cookie that contains the user session ID is set during successful login and session data is stored at sever side. Cookie-based authentication must be protected against cross-site request forgery (CSRF) attacks and extra measures must be taken to secure the cookies by serving them only over HTTPS and setting the HttpOnly, Secure and SameSite attributes.

A common alternative to stateful authentication is stateless authentication with JSON Web Tokens (JWT) or secure cookie sessions where the session data resides at the client side browser and is either signed or encrypted. Secure cookie sessions are described in RFC 6896 and in the following article about secure cookie-based Spring Security sessions. Usage of both an anonymous session and a cache is required to store the challenge nonce and the time it was issued before the user is authenticated. The anonymous session must be used for protection against forged login attacks by guaranteeing that the authentication token is received from the same browser to which the corresponding challenge nonce was issued. The cache must be used for protection against replay attacks by guaranteeing that each authentication token can be used exactly once.

Challenge nonce generation

The authentication protocol requires support for generating challenge nonces, large random numbers that can be used only once, and storing them for later use during token validation. The validation library uses the java.security.SecureRandom API as the secure random source and the ChallengeNonceStore interface for storing issued challenge nonces.

The -Djava.security.egd=file:/dev/./urandom command line argument is added to pom.xml to avoid the risk of having the code execution blocked unexpectedly during random generation. Without this, the JVM uses /dev/random, which can block, to seed the SecureRandom class.

The authentication protocol requires a filter that issues challenge nonces as described in section 6. Add a filter for issuing challenge nonces.

Nonce usage is described in more detail in the Web eID system architecture document.

Basic usage

As described in section 3. Configure the challenge nonce generator, the only mandatory configuration parameter of the challenge nonce generator is the challenge nonce store.

The challenge nonce store is used to save the nonce value along with the nonce expiry time. It must be possible to look up the challenge nonce data structure from the store using an identifier specific to the browser session. The values from the store are used by the token validator as described in the section Authentication token validation > Basic usage that also contains recommendations for store usage and configuration.

The nonce generator configuration and construction is described in more detail in section 3. Configure the challenge nonce generator. Once the generator object has been constructed, it can be used for generating nonces as follows:

ChallengeNonce challengeNonce = nonceGenerator.generateAndStoreNonce();  

The generateAndStoreNonce() method both generates the nonce and saves it in the store.

Extended configuration

The following additional configuration options are available in ChallengeNonceGeneratorBuilder:

  • withNonceTtl(Duration duration) – overrides the default challenge nonce time-to-live duration. When the time-to-live passes, the nonce is considered to be expired. Default challenge nonce time-to-live is 5 minutes.
  • withSecureRandom(SecureRandom) - allows to specify a custom SecureRandom instance.

Extended configuration example:

ChallengeNonceGenerator generator = new ChallengeNonceGeneratorBuilder()
    .withChallengeNonceStore(store)
    .withNonceTtl(Duration.ofMinutes(5))
    .withSecureRandom(customSecureRandom)
    .build();

Differences between version 1 and version 2

In version 1, the generated challenge nonces were stored in a JSR107 compatible cache. The goal of using a cache was to support stateful and stateless authentication with a universal API that uses the same underlying mechanism. However, in case the website had a CSRF vulnerability, this made the solution vulnerable to forged login attacks (the attacker could trick the victim to submit the authentication token with the attacker's challenge nonce to the website using a CSRF attack, so that the victim was authenticated to the website as the attacker). To mitigate this attack, in version 2 the requirement is that the library adopter must guarantee that the authentication token is received from the same browser to which the corresponding challenge nonce was issued. The recommended solution is to use a session-backed challenge nonce store, as in the code examples above. The library no longer uses the JSR107 cache API and provides a ChallengeNonceStore interface instead.

In the internal implementation, the Web eID authentication token format changed in version 2. In version 1, the authentication token was in the OpenID X509 ID Token (JWT) format in order to be compatible with the standard OpenID Connect ID Token specification. During independent security review it was pointed out that any similarities of the Web eID authentication token to the JWT format are actually undesirable, as they would imply that the claims presented in the Web eID authentication token can be trusted and processed, while in fact they must be ignored, as they can be manipulated at the client side. The presence of the claims in the authentication token introduces a risk of vulnerabilities in case the authentication implementer decides to rely on any of them for making security critical decisions or decides to apply the same standard validation workflow that is applied to standard JWTs. Since there does not exist a standardized format for an authentication proof that corresponds to the requirements of the Web eID authentication protocol, a special purpose JSON-based format for the Web eID authentication token was adopted in version 2. The format is described in detail in the section Authentication token format, and the full analysis of the format change is available in this article.

Authentication token format versions

The Web eID authentication protocol defines two token formats currently supported by this library:

  • Format v1.0 – Used in desktop Web eID authentication flows with traditional smart card readers.

  • Format v1.1 – An extended authentication token format that allows signing certificate information to be included in the authentication response.

    • unverifiedSigningCertificates – an array of signing certificate entries. Each entry contains:
      • certificate – a base64-encoded DER-encoded signing certificate;
      • supportedSignatureAlgorithms – a list of supported signature algorithms associated with that certificate;

Both token formats follow the same validation principles, differing only in the structure of embedded certificates and the additional verification steps required for v1.1.

About

Web eID authentication token validation library for Java

Resources

Contributing

Stars

3 stars

Watchers

9 watching

Forks

Releases

Packages

Used by

Contributors

Languages