001 package com.nimbusds.oauth2.sdk.auth; 002 003 004 import java.nio.charset.Charset; 005 import java.util.Date; 006 007 import org.apache.commons.lang3.ArrayUtils; 008 import org.apache.commons.lang3.RandomStringUtils; 009 import org.apache.commons.lang3.StringUtils; 010 011 012 /** 013 * Secret or password. The secret should be {@link #erase erased} when no 014 * longer in use. 015 * 016 * @author Vladimir Dzhuvinov 017 */ 018 public class Secret { 019 020 021 /** 022 * The secret value. 023 */ 024 private byte[] value; 025 026 027 /** 028 * Optional expiration date. 029 */ 030 private final Date expDate; 031 032 033 /** 034 * Creates a new secret with the specified value. 035 * 036 * @param value The value. Must not be {@code null} or empty string. 037 */ 038 public Secret(final String value) { 039 040 this(value, null); 041 } 042 043 044 /** 045 * Creates a new secret with the specified value. 046 * 047 * @param value The value. Must not be {@code null} or empty array. 048 */ 049 public Secret(final byte[] value) { 050 051 this(value, null); 052 } 053 054 055 /** 056 * Creates a new secret with the specified value and expiration date. 057 * 058 * @param value The value. Must be UTF-8 encoded, not {@code null} or 059 * * empty string. 060 * @param expDate The expiration date, {@code null} if not specified. 061 */ 062 public Secret(final String value, final Date expDate) { 063 064 if (StringUtils.isBlank(value)) 065 throw new IllegalArgumentException("The value must not be null or empty string"); 066 067 this.value = value.getBytes(Charset.forName("utf-8")); 068 069 this.expDate = expDate; 070 } 071 072 073 /** 074 * Creates a new secret with the specified value and expiration date. 075 * 076 * @param value The value. Must not be {@code null} or empty string. 077 * @param expDate The expiration date, {@code null} if not specified. 078 */ 079 public Secret(final byte[] value, final Date expDate) { 080 081 if (ArrayUtils.isEmpty(value)) 082 throw new IllegalArgumentException("The value must not be null or empty array"); 083 084 this.value = value; 085 086 this.expDate = expDate; 087 } 088 089 090 /** 091 * Creates a new secret with a randomly generated value of the 092 * specified length. The value will be made up of mixed-case 093 * alphanumeric ASCII characters. 094 * 095 * @param length The number of characters. Must be a positive integer. 096 */ 097 public Secret(final int length) { 098 099 this(RandomStringUtils.randomAlphanumeric(length)); 100 } 101 102 103 /** 104 * Creates a new secret with a randomly generated value. The value will 105 * be made up of 32 mixed-case alphanumeric ASCII characters. 106 */ 107 public Secret() { 108 109 this(32); 110 } 111 112 113 /** 114 * Gets the value of this secret. 115 * 116 * @return The value as a UTF-8 encoded string, {@code null} if it has 117 * been erased. 118 */ 119 public String getValue() { 120 121 if (ArrayUtils.isEmpty(value)) 122 return null; 123 124 return new String(value, Charset.forName("utf-8")); 125 } 126 127 128 /** 129 * Gets the value of this secret. 130 * 131 * @return The value as a byte array, {@code null} if it has 132 * been erased. 133 */ 134 public byte[] getValueBytes() { 135 136 return value; 137 } 138 139 140 /** 141 * Erases of the value of this secret. 142 */ 143 public void erase() { 144 145 if (ArrayUtils.isEmpty(value)) 146 return; 147 148 for (int i=0; i < value.length; i++) 149 value[i] = 0; 150 151 value = null; 152 } 153 154 155 /** 156 * Gets the expiration date of this secret. 157 * 158 * @return The expiration date, {@code null} if not specified. 159 */ 160 public Date getExpirationDate() { 161 162 return expDate; 163 } 164 165 166 /** 167 * Checks is this secret has expired. 168 * 169 * @return {@code true} if the secret has an associated expiration date 170 * which is in the past (according to the current system time), 171 * else returns {@code false}. 172 */ 173 public boolean expired() { 174 175 if (expDate == null) 176 return false; 177 178 final Date now = new Date(); 179 180 if (expDate.after(now)) 181 return false; 182 else 183 return true; 184 } 185 186 187 188 /** 189 * Overrides {@code Object.equals()}. 190 * 191 * @param object The object to compare to. 192 * 193 * @return {@code true} if the objects are secrets the same value, 194 * otherwise {@code false}. 195 */ 196 @Override 197 public boolean equals(final Object object) { 198 199 return object != null && 200 object instanceof Secret && 201 this.getValue().equals(((Secret)object).getValue()); 202 } 203 }