All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.xillium.gear.auth.NonceShop Maven / Gradle / Ivy

There is a newer version: 1.2.2
Show newest version
package org.xillium.gear.auth;

import java.util.*;
import java.security.SecureRandom;
import org.xillium.base.Perishable;
import org.xillium.base.beans.Strings;


/**
 * NonceShop is a producer of nonce values used in authentication/verification.
 */
public class NonceShop {

    /**
     * Constructs a NonceShop running on a JVM instance with a TTL and of a given byte size.
     *
     * @param instance the instance number of this JVM
     * @param ttl the default time-to-live in milliseconds for each nonce produced
     * @param size the byte size of nonces
     */
    public NonceShop(byte instance, long ttl, byte size) {
        INSTANCE = instance;
        TTL = ttl;
        SIZE = size;
    }

    /**
     * Reports nonce TTL.
     *
     * @return the default nonce TTL
     */
    public long getTimeToLive() {
        return TTL;
    }

    /**
     * Produces a nonce of an arbitrary size in bytes, which is not to be proved later.
     *
     * @param size the size of the nonce in bytes
     * @return the new nonce as a hexadecimal string
     */
    public String produce(int size) {
        byte bytes[] = new byte[size];
        _random.nextBytes(bytes);
        return Strings.toHexString(bytes);
    }

    /**
     * Produces a nonce that is associated with the given state and is to be proved within a time limit.
     *
     * @param state an arbitrary state to be associated with the new nonce.
     * @param time the TTL of the new nonce, in milliseconds. If this parameter is 0 or negative, the default TTL is used instead.
     * @return the new nonce as a hexadecimal string
     */
    public String produce(String state, long time) {
        Nonce nonce = new Nonce(INSTANCE, time > 0 ? time : TTL, SIZE, _random);
        _map.put(state + ':' + nonce.value, nonce);
        return nonce.value;
    }

    /**
     * Renews a nonce. The nonce must be valid and must have not expired.
     */
    public boolean renew(String value, String state, long time) {
        Nonce nonce = _map.get(state + ':' + value);
        if (nonce != null && !nonce.hasExpired()) {
            nonce.renew(time > 0 ? time : TTL);
            return true;
        } else {
            return false;
        }
    }

    /**
     * Proves a nonce and its associated state. A nonce can only be successfully proved once.
     *
     * @param value the nonce value
     * @param state the state associated with the nonce.
     * @return whether the nonce is successfully proved
     */
    public boolean prove(String value, String state) {
        Nonce nonce = _map.remove(state + ':' + value);
        return nonce != null && !nonce.hasExpired();
    }

    private static class Nonce implements Perishable {
        final String value;
        long expiration;

        Nonce(byte instance, long time, int size, SecureRandom random) {
            byte bytes[] = new byte[size];
            random.nextBytes(bytes);
            bytes[0] = instance;
            value = Strings.toHexString(bytes);
            expiration = System.currentTimeMillis() + time;
        }

        void renew(long time) {
            expiration = System.currentTimeMillis() + time;
        }

        @Override
        public boolean hasExpired() {
            return expiration < System.currentTimeMillis();
        }
    }

    private final Map _map = Collections.synchronizedMap(new Perishable.Map());
    private final SecureRandom _random = new SecureRandom();
    private final byte INSTANCE;
    private final byte SIZE;
    private final long TTL;
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy