36a180f064a19613f875a1ea2b7310f90287dbfd
[java-idp.git] / src / edu / internet2 / middleware / shibboleth / wayf / SamlIdPCookie.java
1 /*
2  * Copyright [2005] [University Corporation for Advanced Internet Development, Inc.]
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16
17 package edu.internet2.middleware.shibboleth.wayf;
18
19 import java.util.ArrayList;
20 import java.util.Iterator;
21
22 import javax.servlet.http.Cookie;
23 import javax.servlet.http.HttpServletRequest;
24 import javax.servlet.http.HttpServletResponse;
25
26 import org.bouncycastle.util.encoders.Base64;
27
28 /**
29  * Implementation of the <code>_saml_idp </code> cookie.
30  * 
31  * Note that any SamlIdPCookie is only valid for as long as the reqest/response 
32  * parameters provided to getIdPCookie remain valid.
33  * 
34  * @author Rod Widdowson
35  *
36  */
37 public class SamlIdPCookie  {
38
39         private static final String COOKIE_NAME = "_saml_idp";
40
41         private final HttpServletRequest req;
42         private final HttpServletResponse res;
43         private final String domain;
44         private final ArrayList /*<String>*/ idPList = new ArrayList/*<String>*/();
45         
46         /**
47          * Constructs a <code>SamlIdPCookie</code> from the provided string (which is the raw data 
48          * 
49          * @param codedData
50          *            the information read from the cookie
51          * @param domain - if non null the domain for any *created* cookie.
52          */
53         private SamlIdPCookie(String codedData, HttpServletRequest req, HttpServletResponse res, String domain) {
54                 
55                 this.req = req;
56                 this.res = res;
57                 this.domain = domain;
58                 
59                 int start;
60                 int end;
61                 
62                 if (codedData == null || codedData.equals("")) {
63                         return;
64                 }
65                 //
66                 // Because there are spaces in the data the cookie may be returned enclosed in quotes
67                 //
68                 if (codedData.charAt(0) == '"' && codedData.charAt(codedData.length()-1) == '"') {
69                         codedData= codedData.substring(1,codedData.length()-1);
70                 }
71                 
72                 
73                 start = 0;
74                 end = codedData.indexOf(' ', start);
75                 while (end > 0) {
76                         String value = codedData.substring(start, end);
77                         start = end + 1;
78                         end = codedData.indexOf(' ', start);
79                         if (!value.equals("")) {
80                             idPList.add(new String(Base64.decode(value)));
81                         }
82                 }
83                 if (start < codedData.length()) {
84                         String value = codedData.substring(start);
85                         if (!value.equals("")) {
86                             idPList.add(new String(Base64.decode(value)));
87                         }
88                 }
89         }
90         /**
91          * Create a SamlCookie with no data inside.
92          * @param domain - if non null, the domain of the new cookie 
93          *
94          */
95         public SamlIdPCookie(HttpServletRequest req, HttpServletResponse res, String domain) {
96                 this.req = req;
97                 this.res = res;
98                 this.domain = domain;
99         }
100
101         /**
102          * Add the specified Shibboleth IdP Name to the cookie list or move to 
103          * the front and then write it back.
104          * 
105          * We always add to the front (and remove from wherever it was)
106          * 
107          * @param idPName    - The name to be added
108          * @param expiration - The expiration of the cookie or zero if it is to be unchanged
109          */
110         public void addIdPName(String idPName, int expiration) {
111
112                 idPList.remove(idPName);
113                 idPList.add(0, idPName);
114
115                 writeCookie(expiration);
116         }
117
118         /**
119          * Return an iterator over the list of IdPNames 
120          * @param which
121          * @return
122          */
123
124         public Iterator/*<String>*/ iterator() {
125
126                 return idPList.iterator();
127         }
128         
129         /**
130          * Delete the <b>entire<\b> cookie contents
131          */
132
133         public static void deleteCookie(HttpServletRequest req, HttpServletResponse res) {
134                 Cookie cookie = getCookie(req);
135                 
136                 if (cookie == null) { 
137                         return; 
138                 }
139                 cookie.setMaxAge(0);
140                 res.addCookie(cookie);
141         }
142
143         /**
144          * Load up the cookie and convert it into a SamlIdPCookie.  If there is no
145          * underlying cookie return a null one.
146          * @param domain - if this is set then any <b>created</b> cookies are set to this domain 
147          */
148         
149         public static SamlIdPCookie getIdPCookie(HttpServletRequest req, HttpServletResponse res, String domain) {
150                 Cookie cookie = getCookie(req);
151                 
152                 if (cookie == null) {
153                         return new SamlIdPCookie(req, res, domain);
154                 } else {
155                         return new SamlIdPCookie(cookie.getValue(), req, res, domain);
156                 }
157         }
158
159         /**
160          * Remove origin from the cachedata and write it back.
161          * @param origin
162          */
163         
164         public void deleteIdPName(String origin) {
165                 idPList.remove(origin);
166                 writeCookie(0);
167         }
168
169         private void writeCookie(int expiration)
170         {
171                 Cookie cookie = getCookie(req);
172                 
173                 if (idPList.size() == 0) {
174                         //
175                         // Nothing to write, so delete the cookie
176                         //
177                         cookie.setMaxAge(0);
178                         res.addCookie(cookie);
179                         return;
180                 }
181
182                 //
183                 // Otherwise encode up the cookie
184                 //
185                 
186                 StringBuffer buffer = new StringBuffer();
187                 Iterator /*<String>*/ it = idPList.iterator();
188                 
189                 while (it.hasNext()) {
190                         String next = (String) it.next();
191                         String what = new String(Base64.encode(next.getBytes()));
192                         buffer.append(what).append(' ');
193                 }
194                 
195                 String value = buffer.toString();
196                 
197                 if (cookie == null) { 
198                         cookie = new Cookie(COOKIE_NAME, value);
199                 } else {
200                         cookie.setValue(value);
201                 }
202                 cookie.setComment("Used to cache selection of a user's Shibboleth IdP");
203                 cookie.setPath("/");
204
205                 if (expiration > 0) {
206                         cookie.setMaxAge(expiration);
207                 }
208                 if (domain != null && domain != "") {
209                         cookie.setDomain(domain);
210                 }
211                 res.addCookie(cookie);
212         
213         }
214
215         private static Cookie getCookie(HttpServletRequest req) {
216                 
217                 Cookie[] cookies = req.getCookies();
218                 if (cookies != null) {
219                         for (int i = 0; i < cookies.length; i++) {
220                                 if (cookies[i].getName().equals(COOKIE_NAME)) { 
221                                         return cookies[i];
222                                 }
223                         }
224                 }
225                 return null;
226         }
227 }