1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21 package no.feide.moria.store;
22
23 import java.io.Serializable;
24 import java.util.Date;
25
26 /***
27 * This class represents the tickets used as identifiers in Moria. Each
28 * ticket has a unique key, a type and an associated service.
29 *
30 * These attributes are used for validation and authorization of incoming
31 * requests.
32 *
33 * @author Bjørn Ola Smievoll <b.o@smievoll.no>
34 * @version $Revision: 1.20 $
35 */
36 final class MoriaTicket implements Serializable {
37
38 /*** Generated serial version UID. */
39 private static final long serialVersionUID = 4051047471184687665L;
40
41 /*** The unique identifier of this ticket. */
42 private final String ticketId;
43
44 /*** The type of this ticket. */
45 private final MoriaTicketType ticketType;
46
47 /*** The id of the service associated with this ticket. */
48 private final String servicePrincipal;
49
50 /*** The time when this ticket expires, stored as milliseconds since epoch. */
51 private final Long expiryTime;
52
53 /*** The data associated with this ticket. */
54 private final MoriaStoreData data;
55
56 /*** The userorg associated with this ticket. */
57 private String userorg;
58
59 /***
60 * Constructs a new ticket with auto-generated ticket id.
61 *
62 * @param ticketType
63 * the type of ticket
64 * @param nodeId
65 * the id of the node creating this ticket
66 * @param servicePrincipal
67 * the id of the service this ticket relates to
68 * @param expiryTime
69 * the time when this ticket expires (in milliseconds since Epoch)
70 * @param data
71 * the data object associated with this ticket. May be null
72 * @param userorg
73 * the userorg associated with this ticket. Can be null if unknown.
74 */
75 MoriaTicket(final MoriaTicketType ticketType, final String nodeId, final String servicePrincipal,
76 final Long expiryTime, final MoriaStoreData data, final String userorg) {
77 this(MoriaTicket.newId(nodeId), ticketType, servicePrincipal, expiryTime, data, userorg);
78 }
79
80 /***
81 * Constructs a new ticket with the given arguments.
82 *
83 * @param ticketId
84 * A key identifying this ticket.
85 * @param ticketType
86 * The type of ticket.
87 * @param servicePrincipal
88 * The id of the service this ticket relates to. Must be null
89 * for SSO tickets, but not null or zero length for other
90 * ticket types.
91 * @param expiryTime
92 * The time when this ticket expires (in milliseconds since Epoch).
93 * @param data
94 * The data object associated with this ticket. May be null.
95 * Must be MoriaAuthnAttempt for login and service tickets, and
96 * CachedUserData for SSO, TGT and proxy tickets.
97 * @param userorg
98 * The userorg associated with this ticket. Can be null if unknown.
99 * @throws IllegalArgumentException
100 * If ticketId is null or zero length, if ticketType is null, if
101 * servicePrincipal or data is inappropriate for the ticketType
102 * or if expiryTime is in the past.
103 */
104 MoriaTicket(final String ticketId, final MoriaTicketType ticketType, final String servicePrincipal, final Long expiryTime,
105 final MoriaStoreData data, final String userorg) {
106
107
108 if (ticketId == null || ticketId.equals(""))
109 throw new IllegalArgumentException("ticketId cannot be null or an empty string");
110 this.ticketId = ticketId;
111
112 if (ticketType == null)
113 throw new IllegalArgumentException("ticketType cannot be null");
114 this.ticketType = ticketType;
115
116
117 if (!ticketType.equals(MoriaTicketType.SSO_TICKET) && (servicePrincipal == null || servicePrincipal.equals("")))
118 throw new IllegalArgumentException("servicePrincipal cannot be null or empty string");
119
120 if (ticketType.equals(MoriaTicketType.SSO_TICKET) && servicePrincipal != null)
121 throw new IllegalArgumentException("servicePrincipal must be null when creating an SSO ticket");
122 this.servicePrincipal = servicePrincipal;
123
124
125
126 if (expiryTime == null || expiryTime.longValue() < 1072915200000L)
127 throw new IllegalArgumentException("expiryTime must a time in the future");
128 this.expiryTime = expiryTime;
129
130
131 if (data != null) {
132 if (ticketType.equals(MoriaTicketType.LOGIN_TICKET) || ticketType.equals(MoriaTicketType.SERVICE_TICKET)) {
133 if (!(data instanceof MoriaAuthnAttempt)) {
134 throw new IllegalArgumentException("For login and service tickets, data must be MoriaAuthnAttempt");
135 }
136 } else {
137 if (!(data instanceof CachedUserData)) {
138 throw new IllegalArgumentException("For sso, ticket granting and proxy tickets, data must be CachedUserData");
139 }
140 }
141 }
142
143 this.data = data;
144 this.userorg = userorg;
145 }
146
147 /***
148 * Gets the ticket identifier of this ticket.
149 *
150 * @return The key identifying the ticket.
151 */
152 String getTicketId() {
153 return ticketId;
154 }
155
156 /***
157 * Gets the the ticket type of this ticket.
158 *
159 * @return The type of ticket.
160 */
161 MoriaTicketType getTicketType() {
162 return ticketType;
163 }
164
165 /***
166 * Gets the value of the service principal associated with this ticket.
167 *
168 * @return The service principal.
169 */
170 String getServicePrincipal() {
171 return servicePrincipal;
172 }
173
174 /***
175 * Checks the ticket's expiry time versus the current time.
176 *
177 * @return True if the ticket has exceeded its time to live.
178 */
179 boolean hasExpired() {
180 final long now = new Date().getTime();
181
182
183
184
185
186 return expiryTime.longValue() < now;
187 }
188
189 /***
190 * Gets the the expiry time for this ticket.
191 *
192 * @return The expiry time in milliseconds since epoch.
193 */
194 Long getExpiryTime() {
195 return expiryTime;
196 }
197
198 /***
199 * Gets the data object of this ticket.
200 *
201 * @return An instance of MoriaStoreData, or null if no data
202 * object is associated with this ticket.
203 */
204 MoriaStoreData getData() {
205 return data;
206 }
207
208 /***
209 * Tests if ticket is equal to another ticket.
210 * Equality is defined on basis of the ticketId value. Same id, same
211 * ticket.
212 *
213 * @param object
214 * The object to compare with.
215 * @return True if equal.
216 *
217 * @see java.lang.Object#equals(java.lang.Object)
218 */
219 public boolean equals(final Object object) {
220 return (object instanceof MoriaTicket && ((MoriaTicket) object).getTicketId().equals(this.ticketId));
221 }
222
223 /***
224 * Gets the hash code of the ticket.
225 * The hash code is the hash code of the ticketId String.
226 *
227 * @return The hash code.
228 *
229 * @see java.lang.Object#hashCode()
230 */
231 public int hashCode() {
232 return ticketId.hashCode();
233 }
234
235 /***
236 * Gets a string representation of the ticket.
237 *
238 * @return A comma separated string of all the internal values.
239 */
240 public String toString() {
241 return "ticketId: " + ticketId + ", ticketType: " + ticketType + ", servicePrincipal: " + servicePrincipal;
242 }
243
244 /***
245 * Creates a new key that can be used as an identifier of the ticket.
246 *
247 * @return A new unique identifier.
248 */
249 static String newId(final String nodeId) {
250 return RandomId.newId(nodeId);
251 }
252
253 /***
254 * Returns the userorg associated with this ticket, or null if none.
255 * @return The userorg.
256 */
257 public String getUserorg() {
258 return userorg;
259 }
260
261 /***
262 * Associates a userorg with this ticket.
263 * @param org The userorg.
264 */
265 public void setUserorg(final String org) {
266 userorg = org;
267 }
268
269 }