View Javadoc

1   /*
2    * Copyright (c) 2004 UNINETT FAS
3    *
4    * This program is free software; you can redistribute it and/or modify it
5    * under the terms of the GNU General Public License as published by the Free
6    * Software Foundation; either version 2 of the License, or (at your option)
7    * any later version.
8    *
9    * This program is distributed in the hope that it will be useful, but WITHOUT
10   * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11   * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
12   * more details.
13   *
14   * You should have received a copy of the GNU General Public License along with
15   * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
16   * Place - Suite 330, Boston, MA 02111-1307, USA.
17   *
18   * $Id: MoriaTicket.java,v 1.20 2005/03/14 14:26:47 bos Exp $
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         /* Sanity checks on inputs before assignment. */
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         /* Undefined servicePrincipal is only allowed for SSO tickets. */
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         /* 107291520000L equals Thu Jan  1 00:00:00 UTC 2004. */
125         /* TODO: Any reason not to just check against current time with a suitable fuzz factor here? */
126         if (expiryTime == null || expiryTime.longValue() < 1072915200000L)
127             throw new IllegalArgumentException("expiryTime must a time in the future");
128         this.expiryTime = expiryTime;
129 
130         /* Verify that data type matches ticket type. */
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         /* The data object may be null so we just assign. */
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          * If the expiry time is in the future return false, the ticket has not
184          * expired.
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 }