package org.jboss.seam.security.digest; import org.jboss.seam.util.Base64; public class DigestRequest { public static final String DIGEST_REQUEST = "org.jboss.seam.security.digestRequest"; private boolean passwordAlreadyEncoded; private String systemRealm; private String realm; private String key; private String password; private String uri; /** * quality of protection, defined by RFC 2617 */ private String qop; private String nonce; private String nonceCount; private String clientNonce; private String httpMethod; /** * The digest that the client responds with */ private String clientDigest; public String getClientNonce() { return clientNonce; } public void setClientNonce(String clientNonce) { this.clientNonce = clientNonce; } public String getNonce() { return nonce; } public void setNonce(String nonce) { this.nonce = nonce; } public String getNonceCount() { return nonceCount; } public void setNonceCount(String nonceCount) { this.nonceCount = nonceCount; } public String getPassword() { return password; } public void setPassword(String password) { this.password = password; } public boolean isPasswordAlreadyEncoded() { return passwordAlreadyEncoded; } public void setPasswordAlreadyEncoded(boolean passwordAlreadyEncoded) { this.passwordAlreadyEncoded = passwordAlreadyEncoded; } public String getQop() { return qop; } public void setQop(String qop) { this.qop = qop; } public String getRealm() { return realm; } public String getSystemRealm() { return systemRealm; } public void setSystemRealm(String systemRealm) { this.systemRealm = systemRealm; } public void setRealm(String realm) { this.realm = realm; } public String getKey() { return key; } public void setKey(String key) { this.key = key; } public String getUri() { return uri; } public void setUri(String uri) { this.uri = uri; } public String getHttpMethod() { return httpMethod; } public void setHttpMethod(String httpMethod) { this.httpMethod = httpMethod; } public String getClientDigest() { return clientDigest; } public void setClientDigest(String clientDigest) { this.clientDigest = clientDigest; } public void validate() throws DigestValidationException { // Check all required parameters were supplied (ie RFC 2069) if (realm == null) throw new DigestValidationException("Mandatory field 'realm' not specified"); if (nonce == null) throw new DigestValidationException("Mandatory field 'nonce' not specified"); if (uri == null) throw new DigestValidationException("Mandatory field 'uri' not specified"); if (clientDigest == null) throw new DigestValidationException("Mandatory field 'response' not specified"); // Check all required parameters for an "auth" qop were supplied (ie RFC 2617) if ("auth".equals(qop)) { if (nonceCount == null) { throw new DigestValidationException("Mandatory field 'nc' not specified"); } if (clientNonce == null) { throw new DigestValidationException("Mandatory field 'cnonce' not specified"); } } String nonceAsText = new String(Base64.decode(nonce)); String[] nonceTokens = nonceAsText.split(":"); if (nonceTokens.length != 2) { throw new DigestValidationException("Nonce should provide two tokens - nonce received: " + nonce); } // Check realm name equals what we expected if (!systemRealm.equals(realm)) { throw new DigestValidationException("Realm name [" + realm + "] does not match system realm name [" + systemRealm + "]"); } long nonceExpiry = 0; try { nonceExpiry = new Long(nonceTokens[0]).longValue(); } catch (NumberFormatException nfe) { throw new DigestValidationException("First nonce token should be numeric, but was: " + nonceTokens[0]); } // To get this far, the digest must have been valid // Check the nonce has not expired // We do this last so we can direct the user agent its nonce is stale // but the request was otherwise appearing to be valid if (nonceExpiry < System.currentTimeMillis()) { throw new DigestValidationException("Nonce has expired", true); } String expectedNonceSignature = DigestUtils.md5Hex(nonceExpiry + ":" + key); if (!expectedNonceSignature.equals(nonceTokens[1])) { throw new DigestValidationException("Nonce token invalid: " + nonceAsText); } } }