Would anyone be interested in assisting in developing a module to authenticate against iTunes U?

Aaron Axelsen, from the University of Wisconsin, has already developed a php script to do this work. I was curious if this was something that could be rolled into a module so that Drupal could be used for user access management to iTunes U.

Here is the code as contributed by Aaron:

<?php
##############################################
#
# iTunes Authentication Class
# URL: http://omega1.uww.edu/itunesu
# Version: 1.2 - 10/29/2007
#
# Written by Aaron Axelsen - axelsena@uww.edu
# University of Wisconsin - Whitewater
#
# Class based on the Apple provided ITunesU.pl
# example script.
#
# REQUIREMENTS:
#
#	PHP: (Tested with 5.1.x and Newer)
#	- php mhash support - http://mhash.sourceforge.net/
#	- php curl support
#
#
##############################################

class itunes {

	/**
	* https://deimos.apple.com/WebObjects/Core.woa/Browse/example.edu
	*
	* @var string
	*/
	private $siteURL;

	/**
	* /abc1234
	*
	* @var string
	*/
	private $debugSuffix;

	/**
	* STRINGOFTHIRTYTWOLETTERSORDIGITS
	*
	* @var string;
	*/
	private $sharedSecret;

	/**
	* Array of credentials applied for the current user
	*
	* @var array
	*/
	private $credentials = array();

	/**
	* Array of roles passed in with config options
	*
	* @var array
	*/
	private $roles = array();

	/**
	* Create iTunes Object
	*/
	public function __construct($config = false) {
		# Set Debug to False
		$this->setDebug(false);

		# If options are passed in at construct time, setup options
		if ($config != false) {
			$this->config($config);
		}
	}

	/**
	* Use Example Credentials
	* This will setup the options to authenticate into Apple's example iTunes U instance
	*/
	public function setupExample() {
		# Site URL - used for basic logins
		$this->siteURL = 'https://deimos.apple.com/WebObjects/Core.woa/Browse/example.edu';

		# Debug Suffix - needed to authenticate for debugging
	      	$this->debugSuffix = '/abc1234';

		# Shared Secret - needed for authentication
		$this->sharedSecret = 'STRINGOFTHIRTYTWOLETTERSORDIGITS';

		# Roles - array of roles used for credential strings - must correspond to what is set in iTunes U
		$this->role['administrator'] = 'Administrator@urn:mace:itunesu.com:sites:example.edu';
	      	$this->role['student'] = 'Student@urn:mace:itunesu.com:sites:example.edu:classes';
	      	$this->role['instructor'] = 'Instructor@urn:mace:itunesu.com:sites:example.edu:classes';

		# Set domain
	      	$this->setDomain();

		# Set Direct URL - used in conjunction with the handle (allows itunes U to launch directly into the specified course)
		$this->setDirectURL();
	}

	/**
	* Set Configuration Options
	* Takes array as input, keys should correspond to variables above
	*
	* @config array $config iTunes configuration options passed into the class
	*/
	public function config($config) {
		foreach ($config as $key=>$val) {
			if (property_exists($this, $key))
				$this->$key = $val;
			else
				trigger_error("Invalid config option: $key", E_USER_WARNING);
		}

		$this->setDomain();
		$this->setDirectURL();
	}

	/**
	* Add credentials
	*
	* @param string $role Name of the role to add
	* @param string $unique Unique identifier for a course (Not required for Admin)
	*/
	public function add($role,$unique = -1) {
		if ($unique == -1)
			$this->addCredentials($this->roles[$role]);
		else
			$this->addCredentials($this->roles[$role].":$unique");
	}

	/**
	* Add's admin credentials for a given user
	* DEPRECATED - Convert to using array based credentials - add()
	*/
	public function addAdminCredentials() {
		$this->addCredentials($this->administratorCredential);
	}

	/**
	* Add Student Credential for a given course
	* DEPRECATED - Convert to using array based credentials - add()
	*/
	public function addStudentCredential($unique) {
		$this->addCredentials($this->studentCredential.":$unique");
	}

	/**
	* Add Instructor Credential for a given course
	* DEPRECATED - Convert to using style array credentials - add()
	*/
	public function addInstructorCredential($unique) {
		$this->addCredentials($this->instructorCredential.":$unique");
	}

	/**
	* Set User Information
	*/
	public function setUser($name, $email, $netid, $userid) {
		$this->name = $name;
		$this->email = $email;
		$this->netid = $netid;
		$this->userid = $userid;
		return true;
	}

	/**
	* Set the Domain
	*
	* Takes the siteURL and splits off the destination, hostname and action path.
	*/
	private function setDomain() {
		$tmpArray = split("/",$this->siteURL);
		$this->siteDomain = $tmpArray[sizeof($tmpArray)-1];
		$this->actionPath = preg_replace("/https:\/\/(.+?)\/.*/",'$1',$this->siteURL);
		$pattern = "/https:\/\/".$this->actionPath."(.*)/";
		$this->hostName = preg_replace($pattern,'$1',$this->siteURL);
		$this->destination = $this->siteDomain;
		return true;
	}

	/**
	* Set Direct URL
	*
	* Sets the Direct URL - If a handle is specified during the authentication process, this URL will be used to
	* launch iTunes U directly into the specified course.
	*/
	private function setDirectURL() {
		$this->directSiteURL = "https://deimos.apple.com/WebObjects/Core.woa/BrowsePrivately/".$this->siteDomain;
	}

	/**
	* Set the Handle
	*
	* Takes the handle as input and forms the get upload url string
	* This is needed for using the API to upload files directly to iTunes U
	*/
	public function setHandle($handleIn) {
		$this->handle = $handleIn;
		$this->getUploadUrl = "http://deimos.apple.com/WebObjects/Core.woa/API/GetUploadURL/".$this->siteDomain.'.'.$this->handle;
		return true;
	}

	/**
	* Get Identity String
	*
	* Combine user identity information into an appropriately formatted string.
	* take the arguments passed into the function copy them to variables
	*/
	private function getIdentityString() {
		# wrap the elements into the required delimiters.
		return sprintf('"%s" <%s> (%s) [%s]', $this->name, $this->email, $this->netid, $this->userid);
	}

	/**
	* Add Credentials to Array
	*
	* Allows to push multiple credientials for a user onto the array
	*/
	private function addCredentials($credentials) {
		array_push($this->credentials,$credentials);
		return true;
	}

	/**
	* Get Credentials String
	*
	* this is equivalent to join(';', @_); this function is present
    	* for consistency with the Java example.
    	* concatenates all the passed in credentials into a string
    	* with a semicolon delimiting the credentials in the string.
	*/
	private function getCredentialsString() {
		#make sure that at least one credential is passed in
		if (sizeof($this->credentials) < 1)
			return false;
		return implode(";",$this->credentials);
	}

	private function getAuthorizationToken() {
		# Create a buffer with which to generate the authorization token.
		$buffer = "";

	        # create the POST Content and sign it
        	$buffer .= "credentials=" . urlencode($this->getCredentialsString());
	        $buffer .= "&identity=" . urlencode($this->identity);
	        $buffer .= "&time=" . urlencode(mktime());

	        # returns a signed message that is sent to the server
		if (function_exists('hash_hmac'))
			$signature = hash_hmac('SHA256', $buffer, $this->sharedSecret);
		else {
            		require_once 'Message/Message.php';
            		$hmac = Message::createHMAC('SHA256', $this->sharedSecret);
            		$signature = $hmac->calc($buffer);
		}
	    	# append the signature to the POST content
		return sprintf("%s&signature=%s", $buffer, $signature);
	}

	/**
	* Invoke Action
	*
	* Send a request to iTunes U and record the response.
	* Net:HTTPS is used to get better control of the encoding of the POST data
	* as HTTP::Request::Common does not encode parentheses and Java's URLEncoder
	* does.
	*/
	public function invokeAction() {
		$this->identity = $this->getIdentityString();
		$this->token = $this->getAuthorizationToken();

		if (function_exists('curl_init')) {
			$ch = curl_init();
			curl_setopt($ch, CURLOPT_URL, $this->generateURL() . '?' . $this->token);
			curl_setopt($ch, CURLOPT_POST, 1);

			if (curl_exec($ch)) {
		                // Echo Javascript to clear contents of popup window
        		        echo "<script type=\"text/javascript\">
                		<!--
	                	document.getElementById('loading').innerHTML = '';
        	        	-->
                		</script>";
				curl_close($ch);
				return true;
			} else {
				curl_close($ch);
				return false;
			}
		} else {
        		require_once 'HTTP/Request.php';
            		$req = &new HTTP_Request($this->generateURL());;
            		$req->setMethod(HTTP_REQUEST_METHOD_POST);
            		$req->addHeader("Content-Type","application/x-www-form-urlencoded");
            		$req->addHeader("charset","UTF-8");
            		$req->addRawPostData($this->token, true);

            		$x = $req->sendRequest();

            		if (PEAR::isError($x)) {
                		echo $x->getMessage();
                		// Return false if error
                		return false;
            		} else {
                		echo $req->getResponseBody();
                		// Echo Javascript to clear contents of popup window
                		echo "<script type=\"text/javascript\">
                		<!--
                		document.getElementById('loading').innerHTML = '';
                		-->
                		</script>";
                		// Return true if success
                		return true;
            		}
		}
	}

	/**
	* Auth and Upload File to iTunes U
	*
        * This method is said to not be as heavily tested by apple, so you may have
	* unexpected results.
	*
	* $fileIn - full system path to the file you desire to upload
	*/
	public function uploadFile($fileIn) {
                $this->identity = $this->getIdentityString();
                $this->token = $this->getAuthorizationToken();

		// Escape the filename
		$f = escapeshellcmd($fileIn);

		// Contact Apple and Get the Upload URL
		$upUrl = curl_init($this->getUploadUrl.'?'.$this->token);
		curl_setopt($upUrl, CURLOPT_RETURNTRANSFER, true);
		$uploadURL = curl_exec($upUrl);

		$error = curl_error($upUrl);
		$http_code = curl_getinfo($upUrl ,CURLINFO_HTTP_CODE);

		curl_close($upUrl);

                print $http_code;
                print "<br /><br />$uploadURL";
                if ($error) {
                   print "<br /><br />$error";
                }

		# Currently not working using php/curl functions.  For now, we are just going to echo a system command .. see below
		#// Push out the designated file to iTunes U
		#// Build Post Fields
		#$postfields = array("file" => "@$fileIn");

		#$pushUrl = curl_init($uploadURL);
		#curl_setopt($pushUrl, CURLOPT_FAILONERROR, 1);
		#curl_setopt($pushUrl, CURLOPT_FOLLOWLOCATION, 1);// allow redirects
		#curl_setopt($pushUrl, CURLOPT_VERBOSE, 1);
		#curl_setopt($pushUrl, CURLOPT_RETURNTRANSFER, true);
		#curl_setopt($pushUrl, CURLOPT_POST, true);
		#curl_setopt($pushUrl, CURLOPT_POSTFILEDS, $postfields);
		#$output = curl_exec($pushUrl);
		#$error = curl_error($pushUrl);
		#$http_code = curl_getinfo($pushUrl, CURLINFO_HTTP_CODE);

		#curl_close($pushUrl);

		#print "<br/>";
		#print $http_code;
		#print "<br /><br />$output";
		#if ($error) {
		#   print "<br /><br />$error";
		#}

		// Set the php time limit higher so it doesnt time out.
		set_time_limit(1200);

		// System command to initiate curl and upload the file. (Temp until I figure out the php curl commands to do it)
		$command = "curl -S -F file=@$f $uploadURL";

		echo "<br/><br/>";
		echo $command;
		exec($command, $result, $error);
		if ($error) {
			echo "I'm busted";
		} else {
			print_r($result);
		}
		echo $command;
	}

	/**
	* Set Debugging
	*
	* Enable/Disable debugging of iTunes U Authentication
	*/
	public function setDebug($bool) {
		if ($bool) {
			$this->debug = true;
		} else {
			$this->debug = false;
		}
		return true;
	}

	/**
	* Generate Site URL
	*
	* Append debug suffix to end of url if debugging is enabled
	*/
	private function generateURL() {
		if ($this->debug) {
			return $this->siteURL.$this->debugSuffix;
		} elseif ($this->isHandleSet()) {
			return $this->directSiteURL.'.'.$this->handle;
		} else {
			return $this->siteURL;
		}
	}

	/**
	* Check to see if the handle is set
	*/
	private function isHandleSet() {
		if (isset($this->handle))
			return true;
		else
			return false;
	}
}
?>