001: // AclFilter.java
002: // $Id: AclFilter.java,v 1.11 2005/02/18 17:35:13 ylafon Exp $
003: // (c) COPYRIGHT MIT, INRIA and Keio, 1999.
004: // Please first read the full copyright statement in file COPYRIGHT.html
005:
006: package org.w3c.jigsaw.acl;
007:
008: import java.security.Principal;
009: import java.security.acl.Permission;
010: import java.security.acl.Acl;
011:
012: import org.w3c.jigsaw.html.HtmlGenerator;
013: import org.w3c.jigsaw.http.HTTPException;
014: import org.w3c.jigsaw.http.Reply;
015: import org.w3c.jigsaw.http.Request;
016:
017: import org.w3c.tools.resources.Attribute;
018: import org.w3c.tools.resources.AttributeRegistry;
019: import org.w3c.tools.resources.BooleanAttribute;
020: import org.w3c.tools.resources.IntegerAttribute;
021: import org.w3c.tools.resources.LookupResult;
022: import org.w3c.tools.resources.LookupState;
023: import org.w3c.tools.resources.ProtocolException;
024: import org.w3c.tools.resources.ResourceFrame;
025: import org.w3c.tools.resources.ResourceFilter;
026: import org.w3c.tools.resources.RequestInterface;
027: import org.w3c.tools.resources.ReplyInterface;
028: import org.w3c.tools.resources.StringAttribute;
029:
030: import org.w3c.www.http.HTTP;
031: import org.w3c.www.http.HttpChallenge;
032:
033: /**
034: * @version $Revision: 1.11 $
035: * @author Benoît Mahé (bmahe@w3.org)
036: */
037: public class AclFilter extends ResourceFilter {
038:
039: /**
040: * Attribute index - Security level 0=Basic 1=Digest...
041: */
042: protected static int ATTR_SECURITY_LEVEL = -1;
043: /**
044: * Attribute index - The algorithm used
045: */
046: protected static int ATTR_ALGORITHM = -1;
047: /**
048: * Attribute index - The nonce time to live (in seconds)
049: */
050: protected static int ATTR_NONCE_TTL = -1;
051: /**
052: * Attribute index - And or Or for multiple Acls
053: */
054: protected static int ATTR_STRICT_ACL_MERGE_POLICY = -1;
055: /**
056: * Attribute index - Is caching allowed by a shared cache ?
057: */
058: protected static int ATTR_SHARED_CACHABILITY = -1;
059: /**
060: * Attribute index - Is caching allowed in private cache ?
061: */
062: protected static int ATTR_PRIVATE_CACHABILITY = -1;
063: /**
064: * Attribute index - Is public caching of protected documents allowed ?
065: */
066: protected static int ATTR_PUBLIC_CACHABILITY = -1;
067: /**
068: * Attribute index - Do we enable workarounds ?
069: */
070: protected static int ATTR_LENIENT = -1;
071:
072: /**
073: * The JAcl class.
074: */
075: protected static Class JAcl_class = null;
076:
077: protected SecurityLevel security = null;
078:
079: static {
080: Attribute a = null;
081: Class c = null;
082: try {
083: c = Class.forName("org.w3c.jigsaw.acl.AclFilter");
084: JAcl_class = Class.forName("org.w3c.jigsaw.acl.JAcl");
085: } catch (Exception ex) {
086: ex.printStackTrace();
087: System.exit(1);
088: }
089: // security level
090: a = new IntegerAttribute("security-level", new Integer(0),
091: Attribute.EDITABLE);
092: ATTR_SECURITY_LEVEL = AttributeRegistry.registerAttribute(c, a);
093: // do we use a strict acl merge policy
094: a = new BooleanAttribute("strict-acl-merge-policy",
095: Boolean.TRUE, Attribute.EDITABLE);
096: ATTR_STRICT_ACL_MERGE_POLICY = AttributeRegistry
097: .registerAttribute(c, a);
098: // The algorithm used for digest and checksum
099: a = new StringAttribute("algorithm", null, Attribute.EDITABLE);
100: ATTR_ALGORITHM = AttributeRegistry.registerAttribute(c, a);
101: a = new IntegerAttribute("nonce_ttl", new Integer(300),
102: Attribute.EDITABLE);
103: ATTR_NONCE_TTL = AttributeRegistry.registerAttribute(c, a);
104: // Can protected documents be saved in shared cache ?
105: a = new BooleanAttribute("shared-cachability", Boolean.FALSE,
106: Attribute.EDITABLE);
107: ATTR_SHARED_CACHABILITY = AttributeRegistry.registerAttribute(
108: c, a);
109: // Can protected documents be shared in private cache ?
110: a = new BooleanAttribute("private-cachability", Boolean.FALSE,
111: Attribute.EDITABLE);
112: ATTR_PRIVATE_CACHABILITY = AttributeRegistry.registerAttribute(
113: c, a);
114: // Can protected documents be publicly cached ?
115: a = new BooleanAttribute("public-cachability", Boolean.FALSE,
116: Attribute.EDITABLE);
117: ATTR_PUBLIC_CACHABILITY = AttributeRegistry.registerAttribute(
118: c, a);
119: // Are we lenient in the way we check things ?
120: // related to enabling/disabling workarounds because of some
121: // implementations
122: a = new BooleanAttribute("lenient", Boolean.FALSE,
123: Attribute.EDITABLE);
124: ATTR_LENIENT = AttributeRegistry.registerAttribute(c, a);
125: }
126:
127: /**
128: * Get the security level.
129: * @return an integer;
130: */
131: public int getSecurityLevel() {
132: return getInt(ATTR_SECURITY_LEVEL, 0);
133: }
134:
135: /**
136: * Get the algorithm used
137: */
138: public String getAlgorithm() {
139: return (String) getValue(ATTR_ALGORITHM, "MD5");
140: }
141:
142: public int getNonceTTL() {
143: return getInt(ATTR_NONCE_TTL, 300);
144: }
145:
146: /**
147: * Returns true if we have a strict acl merge policy.
148: * @return a boolean.
149: */
150: public boolean isStrictAclMergePolicy() {
151: return getBoolean(ATTR_STRICT_ACL_MERGE_POLICY, true);
152: }
153:
154: /**
155: * Is this document publicly cachable ?
156: * @return A boolean.
157: */
158: public boolean getPublicCachability() {
159: return getBoolean(ATTR_PUBLIC_CACHABILITY, false);
160: }
161:
162: /**
163: * Is this document cachable in private caches ?
164: * @return A boolean.
165: */
166: public boolean getPrivateCachability() {
167: return getBoolean(ATTR_PRIVATE_CACHABILITY, false);
168: }
169:
170: /**
171: * Is this document cachable in shared caches ?
172: * @return A boolean.
173: */
174: public boolean getSharedCachability() {
175: return getBoolean(ATTR_SHARED_CACHABILITY, false);
176: }
177:
178: /**
179: * Are we lenient in the way we check things?
180: * can be read as "Do we enable workarounds for broken implementations?"
181: * @return A boolean.
182: */
183: public boolean isLenient() {
184: return getBoolean(ATTR_LENIENT, false);
185: }
186:
187: protected JAcl[] getAcls() {
188: ResourceFrame frames[] = collectFrames(JAcl_class);
189: JAcl acls[] = new JAcl[frames.length];
190: for (int i = 0; i < frames.length; i++)
191: acls[i] = (JAcl) frames[i];
192: return acls;
193: }
194:
195: /**
196: * Authenticate the given request for the given client.
197: * This method is invoked prior to any request handling on its target
198: * entity. If the used authentication method allows so, AuthFilters
199: * should set the <strong>authuser</strong> attribute of the request.
200: * @param request The request.
201: * @exception ProtocolException If authentication failed.
202: */
203:
204: public boolean lookup(LookupState ls, LookupResult lr)
205: throws ProtocolException {
206: JAcl acls[] = getAcls();
207: if ((acls == null) || (ls.getRequest() == null)) {
208: return false;
209: }
210: authenticate((Request) ls.getRequest(), acls);
211: return false;
212: }
213:
214: /**
215: * Authenticate the given request.
216: * @param request The request to be authentified.
217: * @param acls The Access Control List array.
218: * @exception org.w3c.tools.resources.ProtocolException if authentication
219: * failed
220: */
221: protected void authenticate(Request request, JAcl acls[])
222: throws ProtocolException {
223: Permission perm = new HTTPPermission(request);
224: Principal princ = security
225: .getPrincipal(request, getAlgorithm());
226: boolean strict = isStrictAclMergePolicy();
227: boolean authorized = false;
228: Acl acl = acls[0];
229:
230: if (princ != null) {
231: if (strict) {
232: authorized = true;
233: for (int i = 0; i < acls.length; i++) {
234: boolean check = acls[i]
235: .checkPermission(princ, perm);
236: if (!check) {
237: authorized = false;
238: acl = acls[i];
239: break;
240: }
241: }
242: } else {
243: for (int i = 0; i < acls.length; i++) {
244: boolean check = acls[i]
245: .checkPermission(princ, perm);
246: if (check) {
247: authorized = true;
248: break;
249: }
250: }
251: }
252: }
253: if (!authorized) {
254: HttpChallenge challenge = security.getChallenge(acl
255: .getName(), princ);
256: Reply e = null;
257: if (request.isProxy()) {
258: e = request.makeReply(HTTP.PROXY_AUTH_REQUIRED);
259: e.setProxyAuthenticate(challenge);
260: } else {
261: e = request.makeReply(HTTP.UNAUTHORIZED);
262: e.setWWWAuthenticate(challenge);
263: }
264: HtmlGenerator g = new HtmlGenerator("Unauthorized");
265: g.append("<h1>Unauthorized access</h1>"
266: + "<p>You are denied access to this resource.");
267: e.setStream(g);
268: request.skipBody();
269: throw new HTTPException(e);
270: } else {
271: security.updateRequestStates(request, princ);
272: }
273: }
274:
275: /**
276: * Add the appropriate cache control directives on the way back.
277: * @param request The request that has been processed.
278: * @param reply The original reply.
279: * @return Always <strong>null</strong>.
280: */
281: public ReplyInterface outgoingFilter(RequestInterface request,
282: ReplyInterface reply) {
283: Reply rep = (Reply) reply;
284: if (getPrivateCachability()) {
285: rep.setMustRevalidate(true);
286: } else if (getSharedCachability()) {
287: rep.setProxyRevalidate(true);
288: } else if (getPublicCachability()) {
289: rep.setPublic(true);
290: }
291: security.updateReply(rep, (Request) request);
292: return null;
293: }
294:
295: /**
296: * Catch set value to maintain cached values.
297: */
298: public void setValue(int idx, Object value) {
299: super .setValue(idx, value);
300: if ((idx == ATTR_SECURITY_LEVEL) || (idx == ATTR_ALGORITHM)
301: || (idx == ATTR_LENIENT)) {
302: security = SecurityLevel.getSecurityLevel(this );
303: }
304: }
305:
306: /**
307: * Initialize the filter.
308: */
309: public void initialize(Object values[]) {
310: super.initialize(values);
311: security = SecurityLevel.getSecurityLevel(this);
312: }
313: }
|