001: /* Copyright 2001 The JA-SIG Collaborative. All rights reserved.
002: * See license distributed with this file and
003: * available online at http://www.uportal.org/license.html
004: */
005:
006: package org.jasig.portal.security.provider;
007:
008: import java.security.MessageDigest;
009:
010: import org.jasig.portal.security.ISecurityContext;
011: import org.jasig.portal.security.PortalSecurityException;
012: import org.apache.commons.logging.Log;
013: import org.apache.commons.logging.LogFactory;
014:
015: /**
016: * <p>This is an implementation of a SecurityContext that checks a user's
017: * credentials against an MD5 hashed password entry.
018: *
019: * @author Andrew Newman, newman@yale.edu
020: * @version $Revision: 34942 $
021: */
022: public class SimpleSecurityContext extends ChainingSecurityContext
023: implements ISecurityContext {
024: private static final Log log = LogFactory
025: .getLog(SimpleSecurityContext.class);
026:
027: private final int SIMPLESECURITYAUTHTYPE = 0xFF02;
028:
029: SimpleSecurityContext() {
030: super ();
031: }
032:
033: public int getAuthType() {
034: return this .SIMPLESECURITYAUTHTYPE;
035: }
036:
037: /**
038: * Authenticate user.
039: * @exception PortalSecurityException
040: */
041: public synchronized void authenticate()
042: throws PortalSecurityException {
043: this .isauth = false;
044: if (this .myPrincipal.UID != null
045: && this .myOpaqueCredentials.credentialstring != null) {
046: String first_name = null, last_name = null, md5_passwd = null;
047:
048: try {
049: String acct[] = AccountStoreFactory
050: .getAccountStoreImpl()
051: .getUserAccountInformation(this .myPrincipal.UID);
052: if (acct[0] != null) {
053:
054: first_name = acct[1];
055: last_name = acct[2];
056: md5_passwd = acct[0];
057: if (!md5_passwd.substring(0, 5).equals("(MD5)")) {
058: log.error("Password not an MD5 hash: "
059: + md5_passwd.substring(0, 5));
060: return;
061: }
062: String txthash = md5_passwd.substring(5);
063: byte[] whole, salt = new byte[8], compare = new byte[16], dgx;
064: whole = decode(txthash);
065: if (whole.length != 24) {
066: log.info("Invalid MD5 hash value");
067: return;
068: }
069: System.arraycopy(whole, 0, salt, 0, 8);
070: System.arraycopy(whole, 8, compare, 0, 16);
071: MessageDigest md = MessageDigest.getInstance("MD5");
072: md.update(salt);
073: dgx = md
074: .digest(this .myOpaqueCredentials.credentialstring);
075: boolean same = true;
076: int i;
077: for (i = 0; i < dgx.length; i++)
078: if (dgx[i] != compare[i])
079: same = false;
080: if (same) {
081: this .myPrincipal.FullName = first_name + " "
082: + last_name;
083: if (log.isInfoEnabled())
084: log.info("User " + this .myPrincipal.UID
085: + " is authenticated");
086: this .isauth = true;
087: } else
088: log.info("MD5 Password Invalid");
089: } else {
090: if (log.isInfoEnabled())
091: log.info("No such user: "
092: + this .myPrincipal.UID);
093: }
094: } catch (Exception e) {
095: PortalSecurityException ep = new PortalSecurityException(
096: "SQL Database Error");
097: log.error("Error authenticating user", e);
098: throw (ep);
099: }
100: }
101: // If the principal and/or credential are missing, the context authentication
102: // simply fails. It should not be construed that this is an error.
103: else {
104: log
105: .info("Principal or OpaqueCredentials not initialized prior to authenticate");
106: }
107: // Ok...we are now ready to authenticate all of our subcontexts.
108: super .authenticate();
109: return;
110: }
111:
112: //
113: // This was originally Jonathan B. Knudsen's Example from his book
114: // Java Cryptography published by O'Reilly Associates (1st Edition 1998)
115: //
116: public static byte[] decode(String base64) {
117: int pad = 0;
118: for (int i = base64.length() - 1; base64.charAt(i) == '='; i--)
119: pad++;
120: int length = base64.length() * 6 / 8 - pad;
121: byte[] raw = new byte[length];
122: int rawIndex = 0;
123: for (int i = 0; i < base64.length(); i += 4) {
124: int block = (getValue(base64.charAt(i)) << 18)
125: + (getValue(base64.charAt(i + 1)) << 12)
126: + (getValue(base64.charAt(i + 2)) << 6)
127: + (getValue(base64.charAt(i + 3)));
128: for (int j = 0; j < 3 && rawIndex + j < raw.length; j++)
129: raw[rawIndex + j] = (byte) ((block >> (8 * (2 - j))) & 0xff);
130: rawIndex += 3;
131: }
132: return raw;
133: }
134:
135: protected static int getValue(char c) {
136: if (c >= 'A' && c <= 'Z')
137: return c - 'A';
138: if (c >= 'a' && c <= 'z')
139: return c - 'a' + 26;
140: if (c >= '0' && c <= '9')
141: return c - '0' + 52;
142: if (c == '+')
143: return 62;
144: if (c == '/')
145: return 63;
146: if (c == '=')
147: return 0;
148: return -1;
149: }
150: }
|