KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > objectweb > easybeans > security > propagation > context > SecurityContext


1 /**
2  * EasyBeans
3  * Copyright (C) 2006 Bull S.A.S.
4  * Contact: easybeans@objectweb.org
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library; if not, write to the Free Software
18  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
19  * USA
20  *
21  * --------------------------------------------------------------------------
22  * $Id: SecurityContext.java 1121 2006-09-27 08:51:06Z benoitf $
23  * --------------------------------------------------------------------------
24  */

25
26 package org.objectweb.easybeans.security.propagation.context;
27
28 import java.io.Serializable JavaDoc;
29 import java.security.Principal JavaDoc;
30 import java.security.acl.Group JavaDoc;
31 import java.util.ArrayList JavaDoc;
32 import java.util.Collections JavaDoc;
33 import java.util.List JavaDoc;
34
35 import javax.security.auth.Subject JavaDoc;
36
37 import org.objectweb.easybeans.log.JLog;
38 import org.objectweb.easybeans.log.JLogFactory;
39 import org.objectweb.easybeans.security.api.EZBSecurityContext;
40 import org.objectweb.easybeans.security.struct.JGroup;
41 import org.objectweb.easybeans.security.struct.JPrincipal;
42
43 /**
44  * Security Context that is exchanged and propagated from clients to beans.<br>
45  * This is also why it is a serializable object (as it has to be exchanged).<br>
46  * The security contains allow to get the current principal and the roles
47  * associated to this principal.<br>
48  * RunAs mode is managed by keeping the previous security context.
49  * @author Florent Benoit
50  */

51 public final class SecurityContext implements EZBSecurityContext, Serializable JavaDoc {
52
53     /**
54      * UID for serialization.
55      */

56     private static final long serialVersionUID = 6612085599241360430L;
57
58     /**
59      * Logger.
60      */

61     private static JLog logger = JLogFactory.getLog(SecurityContext.class);
62
63     /**
64      * Anonymous user name.
65      */

66     private static final String JavaDoc ANONYMOUS_USER = "EasyBeans/Anonymous";
67
68     /**
69      * Anonymous role.
70      */

71     private static final String JavaDoc ANONYMOUS_ROLE = "anonymous";
72
73     /**
74      * Anonymous subject (not authenticated).
75      */

76     private static final Subject JavaDoc ANONYMOUS_SUBJECT = buildAnonymousSubject();
77
78     /**
79      * Current subject (subject that has been authenticated).<br>
80      * By default, it is the anonymous subject.
81      */

82     private Subject JavaDoc subject = ANONYMOUS_SUBJECT;
83
84     /**
85      * caller subject in run-as mode<br>
86      * In run-as case, the run-as subject is set as the current subject, and the
87      * previous one is kept.<br>
88      * This previous subject is used to get the caller on the run-as bean.
89      */

90     private Subject JavaDoc callerInRunAsModeSubject = null;
91
92     /**
93      * Default private constructor.
94      */

95     public SecurityContext() {
96
97     }
98
99     /**
100      * Build a security context with the given subject.
101      * @param subject the given subject.
102      */

103     public SecurityContext(final Subject JavaDoc subject) {
104         this.subject = subject;
105     }
106
107     /**
108      * Enters in run-as mode with the given subject.<br>
109      * The previous subject is stored and will be restored when run-as mode will
110      * be ended.
111      * @param runAsSubject the subject to used in run-as mode.
112      * @return the previous subject.
113      */

114     public Subject JavaDoc enterRunAs(final Subject JavaDoc runAsSubject) {
115         // keep previous
116
this.callerInRunAsModeSubject = subject;
117
118         // update the new one
119
this.subject = runAsSubject;
120
121         // return previous.
122
return callerInRunAsModeSubject;
123     }
124
125     /**
126      * Ends the run-as mode and then restore the context stored by container.
127      * @param oldSubject subject kept by container and restored.
128      */

129     public void endsRunAs(final Subject JavaDoc oldSubject) {
130         this.subject = oldSubject;
131
132         // cancel caller of run-as subject (run-as mode has ended)
133
this.callerInRunAsModeSubject = null;
134     }
135
136     /**
137      * Gets the caller's principal.
138      * @param runAsBean if true, the bean is a run-as bean.
139      * @return principal of the caller.
140      */

141     public Principal JavaDoc getCallerPrincipal(final boolean runAsBean) {
142         Subject JavaDoc subject = null;
143
144         // in run-as mode, needs to return callerInRunAsModeSubject's principal.
145
if (runAsBean && callerInRunAsModeSubject != null) {
146             subject = this.callerInRunAsModeSubject;
147         } else {
148             subject = this.subject;
149         }
150
151         // Then, takes the first principal found. (which is not a role)
152
for (Principal JavaDoc principal : subject.getPrincipals(Principal JavaDoc.class)) {
153             if (!(principal instanceof Group JavaDoc)) {
154                 return principal;
155             }
156         }
157
158         // Principal was not found, severe problem as it should be there. Maybe
159
// the subject was not built correctly.
160
logger.error("No principal found in the current subject. Authentication should have failed when populating subject");
161         throw new IllegalStateException JavaDoc(
162                 "No principal found in the current subject. Authentication should have failed when populating subject");
163     }
164
165     /**
166      * Gets the caller's roles.
167      * @param runAsBean if true, the bean is a run-as bean.
168      * @return list of roles of the caller.
169      */

170     public List JavaDoc<? extends Principal JavaDoc> getCallerRolesList(final boolean runAsBean) {
171         Subject JavaDoc subject = null;
172
173         // in run-as mode, needs to return callerInRunAsModeSubject's principal.
174
if (runAsBean && callerInRunAsModeSubject != null) {
175             subject = this.callerInRunAsModeSubject;
176         } else {
177             subject = this.subject;
178         }
179
180         // Then, takes all the roles found in this principal.
181
for (Principal JavaDoc principal : subject.getPrincipals(Principal JavaDoc.class)) {
182             if (principal instanceof Group JavaDoc) {
183                 return Collections.list(((Group JavaDoc) principal).members());
184             }
185         }
186
187         // Principal was not found, severe problem as it should be there. Maybe
188
// the subject was not built correctly.
189
logger.error("No role found in the current subject. Authentication should have failed when populating subject");
190         throw new IllegalStateException JavaDoc(
191                 "No role found in the current subject. Authentication should have failed when populating subject");
192     }
193
194     /**
195      * Gets the caller's roles.
196      * @param runAsBean if true, the bean is a run-as bean.
197      * @return array of roles of the caller.
198      */

199     public Principal JavaDoc[] getCallerRoles(final boolean runAsBean) {
200         List JavaDoc<? extends Principal JavaDoc> callerRoles = getCallerRolesList(runAsBean);
201         return callerRoles.toArray(new Principal JavaDoc[callerRoles.size()]);
202     }
203
204     /**
205      * Build an anonymous subject when no user is authenticated.<br>
206      * This is required as getCallerPrincipal() should never return null.
207      * @return anonymous subject.
208      */

209     private static Subject JavaDoc buildAnonymousSubject() {
210         return buildSubject(ANONYMOUS_USER, new String JavaDoc[] {ANONYMOUS_ROLE});
211     }
212
213
214     /**
215      * Build a subject with the given user name and the list of roles.<br>
216      * @param userName given username
217      * @param roleArray given array of roles.
218      * @return built subject.
219      */

220     public static Subject JavaDoc buildSubject(final String JavaDoc userName, final String JavaDoc[] roleArray) {
221         List JavaDoc<String JavaDoc> roles = new ArrayList JavaDoc<String JavaDoc>();
222         if (roleArray != null) {
223             for (String JavaDoc role : roleArray) {
224                 roles.add(role);
225             }
226         }
227         return buildSubject(userName, roles);
228     }
229
230     /**
231      * Build a subject with the given user name and the list of roles.<br>
232      * @param userName given username
233      * @param roleList given list of roles.
234      * @return built subject.
235      */

236     public static Subject JavaDoc buildSubject(final String JavaDoc userName, final List JavaDoc<String JavaDoc> roleList) {
237         Subject JavaDoc subject = new Subject JavaDoc();
238
239         // Add principal name
240
Principal JavaDoc principalName = new JPrincipal(userName);
241         subject.getPrincipals().add(principalName);
242
243         // Add roles for this principal
244
Group JavaDoc roles = new JGroup("roles");
245         if (roleList != null) {
246             for (String JavaDoc role : roleList) {
247                 roles.addMember(new JPrincipal(role));
248             }
249         }
250         subject.getPrincipals().add(roles);
251
252         return subject;
253     }
254
255 }
256
Popular Tags