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