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.auth; 019 020 021import java.nio.charset.Charset; 022import java.security.SecureRandom; 023import java.util.Arrays; 024import java.util.Date; 025 026import com.nimbusds.jose.util.Base64URL; 027import net.jcip.annotations.Immutable; 028import org.apache.commons.lang3.ArrayUtils; 029 030 031/** 032 * Secret or password. The secret should be {@link #erase erased} when no 033 * longer in use. 034 */ 035@Immutable 036public class Secret { 037 038 039 /** 040 * The default byte length of generated secrets. 041 */ 042 public static final int DEFAULT_BYTE_LENGTH = 32; 043 044 045 /** 046 * The secure random generator. 047 */ 048 private static final SecureRandom SECURE_RANDOM = new SecureRandom(); 049 050 051 /** 052 * The secret value. 053 */ 054 private byte[] value; 055 056 057 /** 058 * Optional expiration date. 059 */ 060 private final Date expDate; 061 062 063 /** 064 * Creates a new secret with the specified value. 065 * 066 * @param value The secret value. May be an empty string. Must be 067 * UTF-8 encoded and not {@code null}. 068 */ 069 public Secret(final String value) { 070 071 this(value, null); 072 } 073 074 075 /** 076 * Creates a new secret with the specified value and expiration date. 077 * 078 * @param value The secret value. May be an empty string. Must be 079 * UTF-8 encoded and not {@code null}. 080 * @param expDate The expiration date, {@code null} if not specified. 081 */ 082 public Secret(final String value, final Date expDate) { 083 084 this.value = value.getBytes(Charset.forName("utf-8")); 085 this.expDate = expDate; 086 } 087 088 089 /** 090 * Creates a new secret with a randomly generated value of the 091 * specified byte length, Base64URL-encoded. 092 * 093 * @param byteLength The byte length of the secret value to generate. 094 * Must be greater than one. 095 */ 096 public Secret(final int byteLength) { 097 098 this(byteLength, null); 099 } 100 101 102 /** 103 * Creates a new secret with a randomly generated value of the 104 * specified byte length, Base64URL-encoded, and the specified 105 * expiration date. 106 * 107 * @param byteLength The byte length of the secret value to generate. 108 * Must be greater than one. 109 * @param expDate The expiration date, {@code null} if not 110 * specified. 111 */ 112 public Secret(final int byteLength, final Date expDate) { 113 114 if (byteLength < 1) 115 throw new IllegalArgumentException("The byte length must be a positive integer"); 116 117 byte[] n = new byte[byteLength]; 118 119 SECURE_RANDOM.nextBytes(n); 120 121 value = Base64URL.encode(n).toString().getBytes(Charset.forName("UTF-8")); 122 123 this.expDate = expDate; 124 } 125 126 127 /** 128 * Creates a new secret with a randomly generated 256-bit (32-byte) 129 * value, Base64URL-encoded. 130 */ 131 public Secret() { 132 133 this(DEFAULT_BYTE_LENGTH); 134 } 135 136 137 /** 138 * Gets the value of this secret. 139 * 140 * @return The value as a UTF-8 encoded string, {@code null} if it has 141 * been erased. 142 */ 143 public String getValue() { 144 145 if (value == null) { 146 return null; // value has been erased 147 } 148 149 return new String(value, Charset.forName("utf-8")); 150 } 151 152 153 /** 154 * Gets the value of this secret. 155 * 156 * @return The value as a byte array, {@code null} if it has 157 * been erased. 158 */ 159 public byte[] getValueBytes() { 160 161 return value; 162 } 163 164 165 /** 166 * Erases of the value of this secret. 167 */ 168 public void erase() { 169 170 if (value == null) { 171 return; // Already erased 172 } 173 174 for (int i=0; i < value.length; i++) { 175 value[i] = 0; 176 } 177 178 value = null; 179 } 180 181 182 /** 183 * Gets the expiration date of this secret. 184 * 185 * @return The expiration date, {@code null} if not specified. 186 */ 187 public Date getExpirationDate() { 188 189 return expDate; 190 } 191 192 193 /** 194 * Checks is this secret has expired. 195 * 196 * @return {@code true} if the secret has an associated expiration date 197 * which is in the past (according to the current system time), 198 * else returns {@code false}. 199 */ 200 public boolean expired() { 201 202 if (expDate == null) { 203 return false; // never expires 204 } 205 206 final Date now = new Date(); 207 208 return expDate.before(now); 209 } 210 211 212 @Override 213 public boolean equals(Object o) { 214 if (this == o) return true; 215 if (!(o instanceof Secret)) return false; 216 217 Secret secret = (Secret) o; 218 219 return Arrays.equals(value, secret.value); 220 221 } 222 223 224 @Override 225 public int hashCode() { 226 return Arrays.hashCode(value); 227 } 228}