1/*
2 * Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation.  Oracle designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Oracle in the LICENSE file that accompanied this code.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
23 * questions.
24 */
25
26package javax.security.auth.kerberos;
27
28import javax.security.auth.Destroyable;
29import java.util.Arrays;
30import java.util.Base64;
31import java.util.Objects;
32
33/**
34 * This class encapsulates a Kerberos 5 KRB_CRED message which can be used to
35 * send Kerberos credentials from one principal to another.<p>
36 *
37 * A KRB_CRED message is defined in Section 5.8.1 of the Kerberos Protocol
38 * Specification (<a href=http://www.ietf.org/rfc/rfc4120.txt>RFC 4120</a>) as:
39 * <pre>
40 *    KRB-CRED        ::= [APPLICATION 22] SEQUENCE {
41 *            pvno            [0] INTEGER (5),
42 *            msg-type        [1] INTEGER (22),
43 *            tickets         [2] SEQUENCE OF Ticket,
44 *            enc-part        [3] EncryptedData -- EncKrbCredPart
45 *    }
46 * </pre>
47 *
48 * @since 9
49 */
50public final class KerberosCredMessage implements Destroyable {
51
52    final private KerberosPrincipal sender;
53    final private KerberosPrincipal recipient;
54    final private byte[] message;
55
56    private boolean destroyed = false;
57
58    /**
59     * Constructs a {@code KerberosCredMessage} object.
60     * <p>
61     * The contents of the {@code message} argument are copied; subsequent
62     * modification of the byte array does not affect the newly created object.
63     *
64     * @param sender the sender of the message
65     * @param recipient the recipient of the message
66     * @param message the DER encoded KRB_CRED message
67     * @throws NullPointerException if any of sender, recipient
68     *                              or message is null
69     */
70    public KerberosCredMessage(KerberosPrincipal sender,
71                               KerberosPrincipal recipient,
72                               byte[] message) {
73        this.sender = Objects.requireNonNull(sender);
74        this.recipient = Objects.requireNonNull(recipient);
75        this.message = Objects.requireNonNull(message).clone();
76    }
77
78    /**
79     * Returns the DER encoded form of the KRB_CRED message.
80     *
81     * @return a newly allocated byte array that contains the encoded form
82     * @throws IllegalStateException if the object is destroyed
83     */
84    public byte[] getEncoded() {
85        if (destroyed) {
86            throw new IllegalStateException("This object is no longer valid");
87        }
88        return message.clone();
89    }
90
91    /**
92     * Returns the sender of this message.
93     *
94     * @return the sender
95     * @throws IllegalStateException if the object is destroyed
96     */
97    public KerberosPrincipal getSender() {
98        if (destroyed) {
99            throw new IllegalStateException("This object is no longer valid");
100        }
101        return sender;
102    }
103
104    /**
105     * Returns the recipient of this message.
106     *
107     * @return the recipient
108     * @throws IllegalStateException if the object is destroyed
109     */
110    public KerberosPrincipal getRecipient() {
111        if (destroyed) {
112            throw new IllegalStateException("This object is no longer valid");
113        }
114        return recipient;
115    }
116
117    /**
118     * Destroys this object by clearing out the message.
119     */
120    @Override
121    public void destroy() {
122        if (!destroyed) {
123            Arrays.fill(message, (byte)0);
124            destroyed = true;
125        }
126    }
127
128    @Override
129    public boolean isDestroyed() {
130        return destroyed;
131    }
132
133    /**
134     * Returns an informative textual representation of this {@code KerberosCredMessage}.
135     *
136     * @return an informative textual representation of this {@code KerberosCredMessage}.
137     */
138    @Override
139    public String toString() {
140        if (destroyed) {
141            return "Destroyed KerberosCredMessage";
142        } else {
143            return "KRB_CRED from " + sender + " to " + recipient + ":\n"
144                    + Base64.getUrlEncoder().encodeToString(message);
145        }
146    }
147
148    /**
149     * Returns a hash code for this {@code KerberosCredMessage}.
150     *
151     * @return a hash code for this {@code KerberosCredMessage}.
152     */
153    @Override
154    public int hashCode() {
155        if (isDestroyed()) {
156            return -1;
157        } else {
158            return Objects.hash(sender, recipient, Arrays.hashCode(message));
159        }
160    }
161
162    /**
163     * Compares the specified object with this {@code KerberosCredMessage}
164     * for equality. Returns true if the given object is also a
165     * {@code KerberosCredMessage} and the two {@code KerberosCredMessage}
166     * instances are equivalent. More formally two {@code KerberosCredMessage}
167     * instances are equal if they have equal sender, recipient, and encoded
168     * KRB_CRED messages.
169     * A destroyed {@code KerberosCredMessage} object is only equal to itself.
170     *
171     * @param other the object to compare to
172     * @return true if the specified object is equal to this
173     * {@code KerberosCredMessage}, false otherwise.
174     */
175    @Override
176    public boolean equals(Object other) {
177        if (other == this) {
178            return true;
179        }
180
181        if (! (other instanceof KerberosCredMessage)) {
182            return false;
183        }
184
185        KerberosCredMessage otherMessage = ((KerberosCredMessage) other);
186        if (isDestroyed() || otherMessage.isDestroyed()) {
187            return false;
188        }
189
190        return Objects.equals(sender, otherMessage.sender)
191                && Objects.equals(recipient, otherMessage.recipient)
192                && Arrays.equals(message, otherMessage.message);
193    }
194}
195