001: // SecurityLevel.java
002: // $Id: SecurityLevel.java,v 1.13 2005/02/21 10:33:05 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.MessageDigest;
010: import java.security.NoSuchAlgorithmException;
011: import java.util.Date;
012:
013: import org.w3c.jigsaw.auth.AuthFilter;
014: import org.w3c.jigsaw.frames.HTTPFrame;
015: import org.w3c.jigsaw.http.Request;
016: import org.w3c.jigsaw.http.Reply;
017: import org.w3c.www.http.HttpChallenge;
018: import org.w3c.www.http.HttpFactory;
019: import org.w3c.tools.resources.FramedResource;
020: import org.w3c.util.StringUtils;
021:
022: /**
023: * @version $Revision: 1.13 $
024: * @author Benoît Mahé (bmahe@w3.org)
025: */
026: public class SecurityLevel {
027:
028: private int level = -1;
029: private long prev_date = 0;
030: private String nonce = null;
031: private String old_nonce = null;
032: private AclFilter filter = null;
033: private HttpChallenge challenge = null;
034: private boolean lenient = false;
035:
036: /**
037: * Get the principal relative to the request and the securityLevel.
038: * @param request the incomming request.
039: * @param securityLevel the Security Level.
040: * @return a Principal instance.
041: */
042: public Principal getPrincipal(Request request, String algo) {
043: Date d;
044: switch (level) {
045: case 0:
046: try {
047: return new BasicAuthPrincipal(request, lenient);
048: } catch (InvalidAuthException ex) {
049: return new HTTPPrincipal(request, lenient);
050: }
051: case 1:
052: d = new Date();
053: if ((d.getTime() - prev_date) / 1000 > filter.getNonceTTL()) {
054: // synchronized to avoid bursts changes
055: synchronized (this ) {
056: if ((d.getTime() - prev_date) / 1000 > filter
057: .getNonceTTL()) {
058: prev_date = d.getTime();
059: updateNonce();
060: }
061: }
062: }
063: try {
064: return new DigestAuthPrincipal(request, nonce,
065: old_nonce, algo);
066: } catch (InvalidAuthException ex) {
067: return new HTTPPrincipal(request);
068: }
069: case 2:
070: default:
071: d = new Date();
072: if ((d.getTime() - prev_date) / 1000 > filter.getNonceTTL()) {
073: // synchronized to avoid bursts changes
074: synchronized (this ) {
075: if ((d.getTime() - prev_date) / 1000 > filter
076: .getNonceTTL()) {
077: prev_date = d.getTime();
078: updateNonce();
079: }
080: }
081: }
082: try {
083: return new DigestQopAuthPrincipal(request, nonce,
084: old_nonce, algo);
085: } catch (InvalidAuthException ex) {
086: try {
087: return new DigestAuthPrincipal(request, nonce,
088: old_nonce, algo);
089: } catch (InvalidAuthException iex) {
090: return new HTTPPrincipal(request);
091: }
092: }
093: }
094: }
095:
096: /**
097: * Get the HTTP challenge relative to the given security level.
098: * @param name the challenge name
099: * @param securityLevel the security level
100: * @return a HttpChallenge instance.
101: */
102: public HttpChallenge getChallenge(String name, Principal principal) {
103: switch (level) {
104: case 0:
105: challenge.setAuthParameter("realm", name);
106: return challenge;
107: case 1:
108: if (principal instanceof DigestAuthPrincipal) {
109: DigestAuthPrincipal dap = (DigestAuthPrincipal) principal;
110: HttpChallenge new_c;
111: if (dap != null && dap.isStale()) {
112: new_c = challenge.getClone();
113: if (new_c != null)
114: new_c.setAuthParameter("stale", "true", false);
115: else
116: new_c = challenge;
117: } else {
118: new_c = challenge;
119: }
120: new_c.setAuthParameter("realm", name);
121: return new_c;
122: } else {
123: challenge.setAuthParameter("realm", name);
124: return challenge;
125: }
126: case 2:
127: default:
128: if (principal instanceof DigestQopAuthPrincipal) {
129: DigestQopAuthPrincipal dap;
130: dap = (DigestQopAuthPrincipal) principal;
131: HttpChallenge new_c;
132: if (dap != null && dap.isStale()) {
133: new_c = challenge.getClone();
134: if (new_c != null) {
135: new_c.setAuthParameter("stale", "true", false);
136: } else {
137: new_c = challenge;
138: }
139: } else {
140: new_c = challenge;
141: }
142: new_c.setAuthParameter("realm", name);
143: Request req = dap.getRequest();
144: String opaque = null;
145: try {
146: MessageDigest md = MessageDigest.getInstance(filter
147: .getAlgorithm());
148: md.update(req.getMethod().getBytes());
149: md.update(nonce.getBytes());
150: byte b[] = md.digest();
151: opaque = StringUtils.toHexString(b);
152: } catch (NoSuchAlgorithmException algex) {
153: opaque = "op" + nonce;
154: }
155: new_c.setAuthParameter("opaque", opaque);
156: return new_c;
157: } else {
158: challenge.setAuthParameter("realm", name);
159: return challenge;
160: }
161: }
162: }
163:
164: public void updateRequestStates(Request request, Principal principal) {
165: switch (level) {
166: case 0:
167: request.setState(AuthFilter.STATE_AUTHUSER, principal
168: .getName());
169: request.setState(AuthFilter.STATE_AUTHTYPE, "Basic");
170: break;
171: case 1:
172: case 2:
173: default:
174: request.setState(AuthFilter.STATE_AUTHUSER, principal
175: .getName());
176: request.setState(AuthFilter.STATE_AUTHTYPE, "Digest");
177: request.setState(AuthFilter.STATE_AUTHCONTEXT, principal);
178: }
179: }
180:
181: public void updateReply(Reply reply, Request request) {
182: switch (level) {
183: case 0:
184: break;
185: case 1:
186: case 2:
187: default:
188: if (request.hasState(AuthFilter.STATE_AUTHCONTEXT)) {
189: DigestAuthPrincipal dap;
190: dap = (DigestAuthPrincipal) request
191: .getState(AuthFilter.STATE_AUTHCONTEXT);
192: if (dap.isStale()) {
193: reply.addAuthenticationInfo("nextnonce", nonce);
194: }
195: }
196: }
197: }
198:
199: private synchronized void updateNonce() {
200: FramedResource fr = filter.getResource();
201: if (fr instanceof HTTPFrame) {
202: HTTPFrame htf = (HTTPFrame) fr;
203: try {
204: MessageDigest md = MessageDigest.getInstance(filter
205: .getAlgorithm());
206: md.update((new Date()).toString().getBytes());
207: try {
208: md.update(htf.getETag().getTag().getBytes());
209: } catch (Exception ex) {
210: // hum... try without it
211: md.update(htf.getURLPath().getBytes());
212: }
213: byte b[] = md.digest();
214: if (nonce != null)
215: old_nonce = nonce;
216: nonce = StringUtils.toHexString(b);
217: challenge.setAuthParameter("nonce", nonce);
218: } catch (NoSuchAlgorithmException algex) {
219: // bad algorithm, prevent access by firing an error
220: }
221: }
222: }
223:
224: private SecurityLevel(AclFilter filter) {
225: String algorithm = null;
226: this .level = filter.getSecurityLevel();
227: this .filter = filter;
228: this .lenient = filter.isLenient();
229: switch (level) {
230: case 0:
231: challenge = HttpFactory.makeChallenge("Basic");
232: challenge.setAuthParameter("realm", "");
233: break;
234: case 1:
235: challenge = HttpFactory.makeChallenge("Digest");
236: //temporary hack for amaya
237: challenge.setAuthParameter("realm", "");
238: challenge.setAuthParameter("domain", filter.getResource()
239: .getURLPath());
240: algorithm = filter.getAlgorithm();
241: if (!algorithm.equalsIgnoreCase("md5")) {
242: challenge.setAuthParameter("algorithm", algorithm,
243: false);
244: }
245: updateNonce();
246: break;
247: case 2:
248: default:
249: challenge = HttpFactory.makeChallenge("Digest");
250: //temporary hack for amaya
251: challenge.setAuthParameter("realm", "");
252: challenge.setAuthParameter("domain", filter.getResource()
253: .getURLPath());
254: algorithm = filter.getAlgorithm();
255: challenge.setAuthParameter("algorithm", algorithm, false);
256: challenge.setAuthParameter("qop", "auth");
257: updateNonce();
258: }
259:
260: }
261:
262: static public SecurityLevel getSecurityLevel(AclFilter filter) {
263: return new SecurityLevel(filter);
264: }
265:
266: }
|