001package com.nimbusds.oauth2.sdk.id;
002
003
004import java.security.SecureRandom;
005
006import org.apache.commons.lang3.StringUtils;
007
008import org.apache.commons.codec.binary.Base64;
009
010import net.minidev.json.JSONAware;
011import net.minidev.json.JSONValue;
012
013
014/**
015 * The base abstract class for representing identifiers and identities. 
016 * Provides constructors that generate Base64URL-encoded secure random 
017 * identifier values.
018 *
019 * <p>Extending classes must override the {@link #equals} method.
020 */
021public abstract class Identifier implements Comparable<Identifier>, JSONAware {
022        
023        
024        /**
025         * The default byte length of generated identifiers.
026         */
027        public static final int DEFAULT_BYTE_LENGTH = 32;
028        
029        
030        /**
031         * The secure random generator.
032         */
033        private static final SecureRandom secureRandom = new SecureRandom();
034
035
036        /**
037         * The identifier value.
038         */
039        private final String value;
040
041
042        /**
043         * Creates a new identifier with the specified value.
044         *
045         * @param value The identifier value. Must not be {@code null} or empty
046         *              string.
047         */
048        public Identifier(final String value) {
049
050                if (StringUtils.isBlank(value))
051                        throw new IllegalArgumentException("The value must not be null or empty string");
052
053                this.value = value;
054        }
055
056
057        /**
058         * Creates a new identifier with a randomly generated value of the 
059         * specified byte length, Base64URL-encoded.
060         *
061         * @param byteLength The byte length of the value to generate. Must be
062         *                   greater than one.
063         */
064        public Identifier(final int byteLength) {
065                
066                if (byteLength < 1)
067                        throw new IllegalArgumentException("The byte length must be a positive integer");
068                
069                byte[] n = new byte[byteLength];
070                
071                secureRandom.nextBytes(n);
072
073                value = Base64.encodeBase64URLSafeString(n);
074        }
075        
076        
077        /**
078         * Creates a new identifier with a randomly generated 256-bit 
079         * (32-byte) value, Base64URL-encoded.
080         */
081        public Identifier() {
082
083                this(DEFAULT_BYTE_LENGTH);
084        }
085
086
087        /**
088         * Returns the value of this identifier.
089         *
090         * @return The value.
091         */
092        public String getValue() {
093
094                return value;
095        }
096
097
098        /**
099         * Returns the JSON string representation of this identifier.
100         *
101         * @return The JSON string.
102         */
103        @Override
104        public String toJSONString() {
105
106                StringBuilder sb = new StringBuilder("\"");
107                sb.append(JSONValue.escape(value));
108                sb.append('"');
109                return sb.toString();
110        }
111        
112        
113        /**
114         * @see #getValue
115         */
116        @Override
117        public String toString() {
118        
119                return getValue();
120        }
121
122
123        @Override
124        public int compareTo(final Identifier other) {
125
126                return getValue().compareTo(other.getValue());
127        }
128
129
130        /**
131         * Overrides {@code Object.hashCode()}.
132         *
133         * @return The object hash code.
134         */
135        @Override
136        public int hashCode() {
137        
138                return value.hashCode();
139        }
140        
141        
142        /**
143         * Overrides {@code Object.equals()}.
144         *
145         * @param object The object to compare to.
146         *
147         * @return {@code true} if the objects have the same value, otherwise
148         *         {@code false}.
149         */
150        @Override
151        public abstract boolean equals(final Object object);
152}