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