[CalendarServer-changes] [1534] PyOpenDirectory/trunk

source_changes at macosforge.org source_changes at macosforge.org
Thu May 17 12:29:35 PDT 2007


Revision: 1534
          http://trac.macosforge.org/projects/calendarserver/changeset/1534
Author:   cdaboo at apple.com
Date:     2007-05-17 12:29:34 -0700 (Thu, 17 May 2007)

Log Message:
-----------
Merge of branches/users/cdaboo/better-errors-1318.

Modified Paths:
--------------
    PyOpenDirectory/trunk/src/CDirectoryService.cpp
    PyOpenDirectory/trunk/src/CDirectoryService.h

Added Paths:
-----------
    PyOpenDirectory/trunk/test_auth.py

Modified: PyOpenDirectory/trunk/src/CDirectoryService.cpp
===================================================================
--- PyOpenDirectory/trunk/src/CDirectoryService.cpp	2007-05-17 16:56:17 UTC (rev 1533)
+++ PyOpenDirectory/trunk/src/CDirectoryService.cpp	2007-05-17 19:29:34 UTC (rev 1534)
@@ -31,8 +31,8 @@
 
 extern PyObject* ODException_class;
 
-# define ThrowIfDSErr(x) { long dirStatus = x; if (dirStatus != eDSNoErr) throw dirStatus; }
-# define ThrowIfNULL(x) { if (x == NULL) throw -1L; }
+# define ThrowIfDSErr(x) { if (x != eDSNoErr) ThrowDSError(x, __FILE__, __LINE__); }
+# define ThrowIfNULL(x) { if (x == NULL) ThrowDSError(-1, __FILE__, __LINE__); }
 
 // This is copied from WhitePages
 #define		kDSStdRecordTypeResources				"dsRecTypeStandard:Resources"
@@ -96,9 +96,9 @@
 		// Get attribute map
 		return _ListAllRecordsWithAttributes(recordType, NULL, attributes);
 	}
-	catch(long dserror)
+	catch(SDirectoryServiceException& dserror)
 	{
-		PyErr_SetObject(ODException_class, Py_BuildValue("((s:i))", "DirectoryServices Error", dserror));		
+		SetPythonException(dserror);
 		return NULL;
 	}
 	catch(...)
@@ -129,9 +129,9 @@
 		// Get attribute map
 		return _QueryRecordsWithAttributes(attr, value, matchType, NULL, casei, recordType, attributes);
 	}
-	catch(long dserror)
+	catch(SDirectoryServiceException& dserror)
 	{
-		PyErr_SetObject(ODException_class, Py_BuildValue("((s:i))", "DirectoryServices Error", dserror));		
+		SetPythonException(dserror);		
 		return NULL;
 	}
 	catch(...)
@@ -160,9 +160,9 @@
 		// Get attribute map
 		return _QueryRecordsWithAttributes(NULL, NULL, 0, query, casei, recordType, attributes);
 	}
-	catch(long dserror)
+	catch(SDirectoryServiceException& dserror)
 	{
-		PyErr_SetObject(ODException_class, Py_BuildValue("((s:i))", "DirectoryServices Error", dserror));		
+		SetPythonException(dserror);
 		return NULL;
 	}
 	catch(...)
@@ -188,9 +188,9 @@
 		result = NativeAuthenticationBasic(guid, user, pswd);
 		return true;
 	}
-	catch(long dserror)
+	catch(SDirectoryServiceException& dserror)
 	{
-		PyErr_SetObject(ODException_class, Py_BuildValue("((s:i))", "DirectoryServices Error", dserror));		
+		SetPythonException(dserror);
 		return false;
 	}
 	catch(...)
@@ -216,9 +216,9 @@
 		result = NativeAuthenticationDigest(guid, user, challenge, response, method);
 		return true;
 	}
-	catch(long dserror)
+	catch(SDirectoryServiceException& dserror)
 	{
-		PyErr_SetObject(ODException_class, Py_BuildValue("((s:i))", "DirectoryServices Error", dserror));		
+		SetPythonException(dserror);	
 		return false;
 	}
 	catch(...)
@@ -390,7 +390,7 @@
 		CloseNode();
 		CloseService();
 	}
-	catch(long dsStatus)
+	catch(SDirectoryServiceException& dsStatus)
 	{
 		// Cleanup
 		if (context != NULL)
@@ -624,7 +624,7 @@
 		CloseNode();
 		CloseService();
 	}
-	catch(long dsStatus)
+	catch(SDirectoryServiceException& dsStatus)
 	{
 		// Cleanup
 		if (context != NULL)
@@ -800,7 +800,7 @@
 		long aDataBufSize = sizeof(long) + ::strlen(user) + sizeof(long) + ::strlen(pswd);
 		authData = ::dsDataBufferAllocate(mDir, aDataBufSize);
 		if (authData == NULL)
-			throw eDSNullDataBuff;
+			ThrowIfDSErr(eDSNullDataBuff);
 		long aCurLength = 0;
 		long aTempLength = ::strlen(user);
 		::memcpy(&(authData->fBufferData[aCurLength]), &aTempLength,  sizeof(long));
@@ -926,7 +926,7 @@
 							sizeof(long) + ::strlen(method);
 		authData = ::dsDataBufferAllocate(mDir, aDataBufSize);
 		if (authData == NULL)
-			throw eDSNullDataBuff;
+			ThrowIfDSErr(eDSNullDataBuff);
 		long aCurLength = 0;
 		long aTempLength = ::strlen(user);
 		::memcpy(&(authData->fBufferData[aCurLength]), &aTempLength,  sizeof(long));
@@ -1009,7 +1009,7 @@
 		if (dirStatus != eDSNoErr)
 		{
 			mDir = 0L;
-			throw dirStatus;
+			ThrowIfDSErr(dirStatus);
 		}
 	}
 }
@@ -1065,7 +1065,7 @@
 		else
 		{
 			result = NULL;
-			throw dirStatus;
+			ThrowIfDSErr(dirStatus);
 		}
 		dirStatus = ::dsDataListDeallocate(mDir, nodePath);
 		free(nodePath);
@@ -1110,7 +1110,7 @@
 		mData = ::dsDataBufferAllocate(mDir, cBufferSize);
 		if (mData == NULL)
 		{
-			throw eDSNullDataBuff;
+			ThrowIfDSErr(eDSNullDataBuff);
 		}
 		mDataSize = cBufferSize;
 	}
@@ -1139,7 +1139,7 @@
 	mData = ::dsDataBufferAllocate(mDir, 2 * mDataSize);
 	if (mData == NULL)
 	{
-		throw eDSNullDataBuff;
+		ThrowIfDSErr(eDSNullDataBuff);
 	}
 	mDataSize *= 2;
 }
@@ -1184,3 +1184,19 @@
 	result[len] = 0;
 	return result;
 }
+
+void CDirectoryService::ThrowDSError(long error, const char* file, long line)
+{
+	CDirectoryService::SDirectoryServiceException dirStatus;
+	dirStatus.mDSError = error;
+	::snprintf(dirStatus.mDescription, 1024, "Exception raised in file %s at line %ld", file, line);
+	throw dirStatus;
+}
+
+void CDirectoryService::SetPythonException(const SDirectoryServiceException& ex)
+{
+	char error[1024];
+	::snprintf(error, 1024, "%s %s", "DirectoryServices Error:", ex.mDescription);
+	PyErr_SetObject(ODException_class, Py_BuildValue("((s:i))", error, ex.mDSError));		
+}
+

Modified: PyOpenDirectory/trunk/src/CDirectoryService.h
===================================================================
--- PyOpenDirectory/trunk/src/CDirectoryService.h	2007-05-17 16:56:17 UTC (rev 1533)
+++ PyOpenDirectory/trunk/src/CDirectoryService.h	2007-05-17 19:29:34 UTC (rev 1534)
@@ -40,6 +40,13 @@
 	bool AuthenticateUserDigest(const char* guid, const char* user, const char* challenge, const char* response, const char* method, bool& result);
 	
 private:
+
+	struct SDirectoryServiceException
+	{
+		long		mDSError;
+		char		mDescription[1024];
+	};
+
 	const char*			mNodeName;
 	tDirReference		mDir;
 	tDirNodeReference	mNode;
@@ -70,4 +77,7 @@
 
 	char* CStringFromBuffer(tDataBufferPtr data);
 	char* CStringFromData(const char* data, size_t len);
+
+	void ThrowDSError(long error, const char* file, long line);
+	void SetPythonException(const SDirectoryServiceException& ex);
 };

Copied: PyOpenDirectory/trunk/test_auth.py (from rev 1533, PyOpenDirectory/branches/users/cdaboo/better-errors-1318/test_auth.py)
===================================================================
--- PyOpenDirectory/trunk/test_auth.py	                        (rev 0)
+++ PyOpenDirectory/trunk/test_auth.py	2007-05-17 19:29:34 UTC (rev 1534)
@@ -0,0 +1,201 @@
+#!/usr/bin/env python
+
+from getpass import getpass
+import opendirectory
+import dsattributes
+import md5
+import sha
+
+algorithms = {
+    'md5': md5.new,
+    'md5-sess': md5.new,
+    'sha': sha.new,
+}
+
+# DigestCalcHA1
+def calcHA1(
+    pszAlg,
+    pszUserName,
+    pszRealm,
+    pszPassword,
+    pszNonce,
+    pszCNonce,
+    preHA1=None
+):
+    """
+    @param pszAlg: The name of the algorithm to use to calculate the digest.
+        Currently supported are md5 md5-sess and sha.
+
+    @param pszUserName: The username
+    @param pszRealm: The realm
+    @param pszPassword: The password
+    @param pszNonce: The nonce
+    @param pszCNonce: The cnonce
+
+    @param preHA1: If available this is a str containing a previously
+       calculated HA1 as a hex string. If this is given then the values for
+       pszUserName, pszRealm, and pszPassword are ignored.
+    """
+
+    if (preHA1 and (pszUserName or pszRealm or pszPassword)):
+        raise TypeError(("preHA1 is incompatible with the pszUserName, "
+                         "pszRealm, and pszPassword arguments"))
+
+    if preHA1 is None:
+        # We need to calculate the HA1 from the username:realm:password
+        m = algorithms[pszAlg]()
+        m.update(pszUserName)
+        m.update(":")
+        m.update(pszRealm)
+        m.update(":")
+        m.update(pszPassword)
+        HA1 = m.digest()
+    else:
+        # We were given a username:realm:password
+        HA1 = preHA1.decode('hex')
+
+    if pszAlg == "md5-sess":
+        m = algorithms[pszAlg]()
+        m.update(HA1)
+        m.update(":")
+        m.update(pszNonce)
+        m.update(":")
+        m.update(pszCNonce)
+        HA1 = m.digest()
+
+    return HA1.encode('hex')
+
+# DigestCalcResponse
+def calcResponse(
+    HA1,
+    algo,
+    pszNonce,
+    pszNonceCount,
+    pszCNonce,
+    pszQop,
+    pszMethod,
+    pszDigestUri,
+    pszHEntity,
+):
+    m = algorithms[algo]()
+    m.update(pszMethod)
+    m.update(":")
+    m.update(pszDigestUri)
+    if pszQop == "auth-int":
+        m.update(":")
+        m.update(pszHEntity)
+    HA2 = m.digest().encode('hex')
+
+    m = algorithms[algo]()
+    m.update(HA1)
+    m.update(":")
+    m.update(pszNonce)
+    m.update(":")
+    if pszNonceCount and pszCNonce and pszQop:
+        m.update(pszNonceCount)
+        m.update(":")
+        m.update(pszCNonce)
+        m.update(":")
+        m.update(pszQop)
+        m.update(":")
+    m.update(HA2)
+    respHash = m.digest().encode('hex')
+    return respHash
+
+
+attempts = 100
+
+realm = "/Search"
+nonce = "128446648710842461101646794502"
+nc = "00000001"
+cnonce = "0a4f113b12345"
+uri = "/principals/"
+method = "GET"
+
+def doAuthDigest(username, password, qop, algorithm):
+    failures = 0
+    
+    result = opendirectory.queryRecordsWithAttribute(
+        od,
+        dsattributes.kDSNAttrRecordName,
+        username,
+        dsattributes.eDSExact,
+        False,
+        dsattributes.kDSStdRecordTypeUsers,
+        [dsattributes.kDS1AttrGeneratedUID])
+    guid = result[username][dsattributes.kDS1AttrGeneratedUID]
+    
+    expected = calcResponse(
+                calcHA1(algorithm, username, realm, password, nonce, cnonce),
+                algorithm, nonce, nc, cnonce, qop, method, uri, None
+            )
+    #print expected
+    
+    if qop:
+        challenge = 'Digest realm="%s", nonce="%s", algorithm=%s, qop="%s"' % (realm, nonce, algorithm, qop,)
+    else:
+        challenge = 'Digest realm="%s", nonce="%s", algorithm=%s' % (realm, nonce, algorithm,)
+    if qop:
+        response = ('Digest username="%s", realm="%s", '
+                'nonce="%s", digest-uri="%s", '
+                'response=%s, algorithm=%s, cnonce="%s", qop=%s, nc=%s' % (username, realm, nonce, uri, expected, algorithm, cnonce, qop, nc, ))
+    else:
+        response = ('Digest username="%s", realm="%s", '
+                'nonce="%s", digest-uri="%s", '
+                'response=%s, algorithm=%s' % (username, realm, nonce, uri, expected, algorithm, ))
+    
+    print "    Challenge: %s" % (challenge,)
+    print "    Response:  %s" % (response, )
+    
+    for x in xrange(attempts):
+        success = opendirectory.authenticateUserDigest(
+            od, 
+            guid,
+            username,
+            challenge,
+            response,
+            method
+        )
+    
+        if not success:
+            failures += 1
+    
+    print "\n%d failures out of %d attempts for Digest.\n\n" % (failures, attempts)
+
+def doAuthBasic(username, password):
+    failures = 0
+    
+    result = opendirectory.queryRecordsWithAttribute(
+        od,
+        dsattributes.kDSNAttrRecordName,
+        username,
+        dsattributes.eDSExact,
+        False,
+        dsattributes.kDSStdRecordTypeUsers,
+        [dsattributes.kDS1AttrGeneratedUID])
+    guid = result[username][dsattributes.kDS1AttrGeneratedUID]
+    
+    for x in xrange(attempts):
+        success = opendirectory.authenticateUserBasic(
+            od, 
+            guid,
+            username,
+            password,
+        )
+    
+        if not success:
+            failures += 1
+    
+    print "\n%d failures out of %d attempts for Basic.\n\n" % (failures, attempts)
+
+search = raw_input("DS search path: ")
+user = raw_input("User: ")
+pswd = getpass("Password: ")
+
+od = opendirectory.odInit(search)
+
+doAuthBasic(user, pswd)
+doAuthDigest(user, pswd, None, "md5")
+#doAuth(user, pswd, "auth", "md5")
+#doAuth(user, pswd, "auth", "md5-sess")
+

-------------- next part --------------
An HTML attachment was scrubbed...
URL: http://lists.macosforge.org/pipermail/calendarserver-changes/attachments/20070517/cc682e22/attachment.html


More information about the calendarserver-changes mailing list