001/*
002 * oauth2-oidc-sdk
003 *
004 * Copyright 2012-2016, Connect2id Ltd and contributors.
005 *
006 * Licensed under the Apache License, Version 2.0 (the "License"); you may not use
007 * this file except in compliance with the License. You may obtain a copy of the
008 * License at
009 *
010 *    http://www.apache.org/licenses/LICENSE-2.0
011 *
012 * Unless required by applicable law or agreed to in writing, software distributed
013 * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
014 * CONDITIONS OF ANY KIND, either express or implied. See the License for the
015 * specific language governing permissions and limitations under the License.
016 */
017
018package com.nimbusds.oauth2.sdk.id;
019
020
021import java.io.Serializable;
022import java.security.SecureRandom;
023import java.util.ArrayList;
024import java.util.Collection;
025import java.util.Collections;
026import java.util.List;
027
028import net.minidev.json.JSONAware;
029import net.minidev.json.JSONValue;
030
031import com.nimbusds.jose.util.Base64URL;
032import com.nimbusds.oauth2.sdk.util.StringUtils;
033
034
035/**
036 * The base class for representing identifiers and identities. Provides
037 * constructors that generate Base64URL-encoded secure random identifier
038 * values.
039 *
040 * <p>Extending classes must override the {@link #equals} method.
041 */
042public class Identifier implements Serializable, Comparable<Identifier>, JSONAware {
043        
044        
045        /**
046         * The default byte length of generated identifiers.
047         */
048        public static final int DEFAULT_BYTE_LENGTH = 32;
049        
050        
051        /**
052         * Returns a string list representation of the specified identifier
053         * collection.
054         *
055         * @param ids The identifiers, {@code null} if not specified.
056         *
057         * @return The string list, empty list if not specified.
058         */
059        public static List<String> toStringList(final Collection<? extends  Identifier> ids) {
060                if (ids == null) {
061                        return Collections.emptyList();
062                }
063                List<String> stringList = new ArrayList<>(ids.size());
064                for (Identifier id: ids) {
065                        stringList.add(id.getValue());
066                }
067                return stringList;
068        }
069        
070        
071        /**
072         * The secure random generator.
073         */
074        protected static final SecureRandom secureRandom = new SecureRandom();
075
076
077        /**
078         * The identifier value.
079         */
080        private final String value;
081
082
083        /**
084         * Creates a new identifier with the specified value.
085         *
086         * @param value The identifier value. Must not be {@code null} or empty
087         *              string.
088         */
089        public Identifier(final String value) {
090
091                if (StringUtils.isBlank(value))
092                        throw new IllegalArgumentException("The value must not be null or empty string");
093
094                this.value = value;
095        }
096
097
098        /**
099         * Creates a new identifier with a randomly generated value of the 
100         * specified byte length, Base64URL-encoded.
101         *
102         * @param byteLength The byte length of the value to generate. Must be
103         *                   greater than one.
104         */
105        public Identifier(final int byteLength) {
106                
107                if (byteLength < 1)
108                        throw new IllegalArgumentException("The byte length must be a positive integer");
109                
110                byte[] n = new byte[byteLength];
111                
112                secureRandom.nextBytes(n);
113
114                value = Base64URL.encode(n).toString();
115        }
116        
117        
118        /**
119         * Creates a new identifier with a randomly generated 256-bit 
120         * (32-byte) value, Base64URL-encoded.
121         */
122        public Identifier() {
123
124                this(DEFAULT_BYTE_LENGTH);
125        }
126
127
128        /**
129         * Returns the value of this identifier.
130         *
131         * @return The value.
132         */
133        public String getValue() {
134
135                return value;
136        }
137
138
139        /**
140         * Returns the JSON string representation of this identifier.
141         *
142         * @return The JSON string.
143         */
144        @Override
145        public String toJSONString() {
146                
147                return  "\"" + JSONValue.escape(value) + '"';
148        }
149        
150        
151        /**
152         * @see #getValue
153         */
154        @Override
155        public String toString() {
156        
157                return getValue();
158        }
159
160
161        @Override
162        public int compareTo(final Identifier other) {
163
164                return getValue().compareTo(other.getValue());
165        }
166
167
168        @Override
169        public boolean equals(final Object o) {
170                if (this == o) return true;
171                if (o == null || getClass() != o.getClass()) return false;
172
173                Identifier that = (Identifier) o;
174
175                return getValue() != null ? getValue().equals(that.getValue()) : that.getValue() == null;
176
177        }
178
179
180        @Override
181        public int hashCode() {
182                return getValue() != null ? getValue().hashCode() : 0;
183        }
184}