001/* 002 * nimbus-jose-jwt 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.jose.jwk; 019 020import com.nimbusds.jose.util.JSONObjectUtils; 021import com.nimbusds.jwt.util.DateUtils; 022import net.jcip.annotations.Immutable; 023 024import java.io.Serializable; 025import java.text.ParseException; 026import java.util.Date; 027import java.util.Map; 028import java.util.Objects; 029 030 031/** 032 * Key revocation. 033 * 034 * @author Vladimir Dzhuvinov 035 * @version 2024-04-27 036 */ 037@Immutable 038public final class KeyRevocation implements Serializable { 039 040 041 /** 042 * Key revocation reason. 043 */ 044 public static class Reason { 045 046 047 /** 048 * General or unspecified reason for the key status change. 049 */ 050 public static final Reason UNSPECIFIED = new Reason("unspecified"); 051 052 053 /** 054 * The private key is believed to have been compromised. 055 */ 056 public static final Reason COMPROMISED = new Reason("compromised"); 057 058 059 /** 060 * The key is no longer active. 061 */ 062 public static final Reason SUPERSEDED = new Reason("superseded"); 063 064 065 /** 066 * The reason value. 067 */ 068 private final String value; 069 070 071 /** 072 * Creates a new reason with the specified value. 073 * 074 * @param value The reason value. Must not be {@code null} 075 */ 076 public Reason(final String value) { 077 this.value = Objects.requireNonNull(value); 078 } 079 080 081 /** 082 * Returns the reason value. 083 * 084 * @return The reason value. 085 */ 086 public String getValue() { 087 return value; 088 } 089 090 091 @Override 092 public String toString() { 093 return getValue(); 094 } 095 096 @Override 097 public boolean equals(Object o) { 098 if (this == o) return true; 099 if (!(o instanceof Reason)) return false; 100 Reason reason = (Reason) o; 101 return Objects.equals(getValue(), reason.getValue()); 102 } 103 104 @Override 105 public int hashCode() { 106 return Objects.hashCode(getValue()); 107 } 108 109 110 /** 111 * Parses a reason from the specified string. 112 * 113 * @param s The string. Must not be {@code null}. 114 * 115 * @return The reason. 116 */ 117 public static Reason parse(final String s) { 118 if (Reason.UNSPECIFIED.getValue().equals(s)) { 119 return Reason.UNSPECIFIED; 120 } else if (Reason.COMPROMISED.getValue().equals(s)) { 121 return Reason.COMPROMISED; 122 } else if (Reason.SUPERSEDED.getValue().equals(s)) { 123 return Reason.SUPERSEDED; 124 } else { 125 return new Reason(s); 126 } 127 } 128 } 129 130 131 /** 132 * The revocation time. 133 */ 134 private final Date revokedAt; 135 136 137 /** 138 * The reason. 139 */ 140 private final Reason reason; 141 142 143 /** 144 * Creates a new key revocation. 145 * 146 * @param revokedAt The revocation time. 147 * @param reason The reason. 148 */ 149 public KeyRevocation(final Date revokedAt, final Reason reason) { 150 this.revokedAt = Objects.requireNonNull(revokedAt); 151 this.reason = reason; 152 } 153 154 155 /** 156 * Returns the revocation time ({@code revoked_at}) parameter. 157 * 158 * @return The revocation time. 159 */ 160 public Date getRevocationTime() { 161 return revokedAt; 162 } 163 164 165 /** 166 * Returns the reason ({@code reason}) parameter. 167 * 168 * @return The reason. 169 */ 170 public Reason getReason() { 171 return reason; 172 } 173 174 175 @Override 176 public boolean equals(Object o) { 177 if (this == o) return true; 178 if (!(o instanceof KeyRevocation)) return false; 179 KeyRevocation that = (KeyRevocation) o; 180 return Objects.equals(revokedAt, that.revokedAt) && Objects.equals(getReason(), that.getReason()); 181 } 182 183 184 @Override 185 public int hashCode() { 186 return Objects.hash(revokedAt, getReason()); 187 } 188 189 190 /** 191 * Returns a JSON object representation of this key revocation. 192 * 193 * @return The JSON object representation. 194 */ 195 public Map<String, Object> toJSONObject() { 196 Map<String, Object> o = JSONObjectUtils.newJSONObject(); 197 o.put("revoked_at", DateUtils.toSecondsSinceEpoch(getRevocationTime())); 198 if (getReason() != null) { 199 o.put("reason", getReason().getValue()); 200 } 201 return o; 202 } 203 204 205 /** 206 * Parses a key revocation from the specified JSON object. 207 * 208 * @param jsonObject The JSON object. Must not be {@code null}. 209 * 210 * @return The key revocation. 211 * 212 * @throws ParseException If parsing failed. 213 */ 214 public static KeyRevocation parse(final Map<String, Object> jsonObject) 215 throws ParseException { 216 Date revokedAt = DateUtils.fromSecondsSinceEpoch(JSONObjectUtils.getLong(jsonObject, "revoked_at")); 217 Reason reason = null; 218 if (jsonObject.get("reason") != null) { 219 reason = Reason.parse(JSONObjectUtils.getString(jsonObject, "reason")); 220 } 221 return new KeyRevocation(revokedAt, reason); 222 } 223}