001/*
002 * acme4j - Java ACME client
003 *
004 * Copyright (C) 2015 Richard "Shred" K├Ârber
005 *   http://acme4j.shredzone.org
006 *
007 * Licensed under the Apache License, Version 2.0 (the "License");
008 * you may not use this file except in compliance with the License.
009 *
010 * This program is distributed in the hope that it will be useful,
011 * but WITHOUT ANY WARRANTY; without even the implied warranty of
012 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
013 */
014package org.shredzone.acme4j.challenge;
015
016import static org.shredzone.acme4j.toolbox.AcmeUtils.base64UrlEncode;
017
018import org.shredzone.acme4j.Login;
019import org.shredzone.acme4j.exception.AcmeProtocolException;
020import org.shredzone.acme4j.toolbox.AcmeUtils;
021import org.shredzone.acme4j.toolbox.JSON;
022import org.shredzone.acme4j.toolbox.JoseUtils;
023
024/**
025 * A generic extension of {@link Challenge} that handles challenges with a {@code token}
026 * and {@code keyAuthorization}.
027 */
028public class TokenChallenge extends Challenge {
029    private static final long serialVersionUID = 1634133407432681800L;
030
031    protected static final String KEY_TOKEN = "token";
032
033    /**
034     * Creates a new generic {@link TokenChallenge} object.
035     *
036     * @param login
037     *            {@link Login} the resource is bound with
038     * @param data
039     *            {@link JSON} challenge data
040     */
041    public TokenChallenge(Login login, JSON data) {
042        super(login, data);
043    }
044
045    /**
046     * Gets the token.
047     */
048    protected String getToken() {
049        var token = getJSON().get(KEY_TOKEN).asString();
050        if (!AcmeUtils.isValidBase64Url(token)) {
051            throw new AcmeProtocolException("Invalid token: " + token);
052        }
053        return token;
054    }
055
056    /**
057     * Computes the key authorization for the given token.
058     * <p>
059     * The default is {@code token + '.' + base64url(jwkThumbprint)}. Subclasses may
060     * override this method if a different algorithm is used.
061     *
062     * @param token
063     *         Token to be used
064     * @return Key Authorization string for that token
065     * @since 2.12
066     */
067    protected String keyAuthorizationFor(String token) {
068        var pk = getLogin().getKeyPair().getPublic();
069        return token + '.' + base64UrlEncode(JoseUtils.thumbprint(pk));
070    }
071
072    /**
073     * Returns the authorization string.
074     * <p>
075     * The default uses {@link #keyAuthorizationFor(String)} to compute the key
076     * authorization of {@link #getToken()}. Subclasses may override this method if a
077     * different algorithm is used.
078     */
079    public String getAuthorization() {
080        return keyAuthorizationFor(getToken());
081    }
082
083}