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 java.security.PublicKey;
019
020import org.shredzone.acme4j.Login;
021import org.shredzone.acme4j.exception.AcmeProtocolException;
022import org.shredzone.acme4j.toolbox.AcmeUtils;
023import org.shredzone.acme4j.toolbox.JSON;
024import org.shredzone.acme4j.toolbox.JoseUtils;
025
026/**
027 * An extension of {@link Challenge} that handles challenges with a {@code token} and
028 * {@code keyAuthorization}.
029 */
030public class TokenChallenge extends Challenge {
031    private static final long serialVersionUID = 1634133407432681800L;
032
033    protected static final String KEY_TOKEN = "token";
034
035    /**
036     * Creates a new generic {@link TokenChallenge} object.
037     *
038     * @param login
039     *            {@link Login} the resource is bound with
040     * @param data
041     *            {@link JSON} challenge data
042     */
043    public TokenChallenge(Login login, JSON data) {
044        super(login, data);
045    }
046
047    /**
048     * Gets the token.
049     */
050    protected String getToken() {
051        String token = getJSON().get(KEY_TOKEN).asString();
052        if (!AcmeUtils.isValidBase64Url(token)) {
053            throw new AcmeProtocolException("Invalid token: " + token);
054        }
055        return token;
056    }
057
058    /**
059     * Computes the key authorization for the given token.
060     * <p>
061     * The default is {@code token + '.' + base64url(jwkThumbprint)}. Subclasses may
062     * override this method if a different algorithm is used.
063     *
064     * @param token
065     *         Token to be used
066     * @return Key Authorization string for that token
067     * @since 2.12
068     */
069    protected String keyAuthorizationFor(String token) {
070        PublicKey pk = getLogin().getKeyPair().getPublic();
071        return token + '.' + base64UrlEncode(JoseUtils.thumbprint(pk));
072    }
073
074    /**
075     * Returns the authorization string.
076     * <p>
077     * The default uses {@link #keyAuthorizationFor(String)} to compute the key
078     * authorization of {@link #getToken()}. Subclasses may override this method if a
079     * different algorithm is used.
080     */
081    public String getAuthorization() {
082        return keyAuthorizationFor(getToken());
083    }
084
085}