#!/usr/bin/perl -w

###############################################################################
# 
# Copyright 2006 Apple Computer, Inc. All rights reserved.
# 
# iTunes U Sample Code License
# IMPORTANT:  This Apple software is supplied to you by Apple Computer, Inc.
# ("Apple") in consideration of your agreement to the following terms, and
# your use, installation, modification or distribution of this Apple software
# constitutes acceptance of these terms.  If you do not agree with these
# terms, please do not use, install, modify or distribute this Apple software.
# 
# In consideration of your agreement to abide by the following terms, and
# subject to these terms, Apple grants you a personal, non-exclusive,
# non-transferable license, under Apple's copyrights in this original Apple
# software (the "Apple Software"), to:  (a) internally use, reproduce, modify
# and internally distribute the Apple Software within your educational
# organization or internal campus network, with or without modifications, in
# binary form for the sole purpose of integrating Apple's iTunes U software
# with your internal campus network systems; and (b) to redistribute the Apple
# Software, in its original form or as modified by you, in binary form to
# other educational organizations participating in the iTunes U program,
# provided that:
#  *
#     (1) if you redistribute the Apple Software in its entirety and without
#         modifications, you must retain this entire notice and the warranty
#         disclaimers and limitation of liability provisions (last two
#         paragraphs below) in all such redistributions of the Apple Software;
#         and
#     (2) if you modify and redistribute the Apple Software, you must indicate
#         that you have made changes to the Apple Software, you must restrict
#         further use of the Apple Software for the sole purpose of
#         integrating Apple's iTunes U software with the recipient's internal
#         campus network systems, and you must include the warranty
#         disclaimers and limitation of liability provisions (last two
#         paragraphs below) in all such redistributions of the Apple Software
#         and/or its derivatives created by you.
# 
# Neither the name, trademarks, service marks or logos of Apple may be used to
# endorse or promote products derived from the Apple Software without specific
# prior written permission from Apple.  Except as expressly stated in this
# notice, no other rights or licenses, express or implied, are granted by
# Apple herein, including but not limited to any patent rights that may be
# infringed by your derivative works or by other works in which the Apple
# Software may be incorporated.
# 
# The Apple Software is provided by Apple on an "AS IS" basis.  APPLE MAKES NO
# WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION THE IMPLIED
# WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS FOR A PARTICULAR
# PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND OPERATION ALONE OR IN
# COMBINATION WITH YOUR PRODUCTS OR SYSTEMS.   Apple is not obligated to
# provide any maintenance, technical or other support for the Apple Software,
# or any updates to you for the Apple Software.
# 
# IN NO EVENT SHALL APPLE BE LIABLE FOR ANY DIRECT, SPECIAL, INDIRECT,
# INCIDENTAL OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
# OR BUSINESS INTERRUPTION) ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION,
# MODIFICATION AND/OR DISTRIBUTION OF THE APPLE SOFTWARE, HOWEVER CAUSED AND
# WHETHER UNDER THEORY OF CONTRACT, TORT (INCLUDING NEGLIGENCE), STRICT
# LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN ADVISED OF THE POSSIBILITY OF
# SUCH DAMAGE.
# 
# Rev.  050406
# 
###############################################################################


###############################################################################
# The ITunesU script permits the secure transmission
# of user credentials and identity between an institution's
# authentication and authorization system and iTunes U.
# 
# The code in this class can be tested by
# running it with the following commands:
# 
#     ./ITunesU.pl
#  
# Changes to values defined in this script's main() method must
# be made before it will succesfully communicate with iTunes U.
#
# In order to run this script you will likely have to install modules from cpan.org
# Instructions for doing this are availble at:
# http://www.perl.com/doc/manual/html/lib/CPAN.html
# The following moduels are required:
#       URI::Escape
#       Digest::SHA
#       Net::HTTP
###############################################################################

use strict;
use Digest::SHA qw(hmac_sha256_hex);
use URI::Escape;
use Net::HTTP;


sub main() {

    # Define your site's information. Replace these
    # values with ones appropriate for your site.
    my $siteURL = "https://deimos.apple.com/WebObjects/Core.woa/Browse/lanecc.edu";
    my $debugSuffix = "/qcp995";
    my $sharedSecret = "GGRQVDVD4M6SBHVVMW6K2YPCX6P3UMEY";
    my $administratorCredential = "Administrator@urn:mace:itunesu.com:sites:lanecc.edu";
    
    # Define the user information. Replace the credentials with the
    # credentials you want to grant to that user, and the optional
    # identity information with the identity of the current user.
    # For initial testing and site setup, use the singe administrator 
    # credential defined when your iTunes U site was created. Once
    # you have access to your iTunes U site, you will be able to define
    # additional credentials and the iTunes U access they provide.
    my @credentialArray = ($administratorCredential);
    my $displayName = "LCC Faculty Webmasters";
    my $emailAddress = "online\@lanecc.edu";
    my $username = "online";
    my $userIdentifier = "42";
        
    # Append your site's debug suffix to the destination if you
    # want to receive an HTML page providing information about
    # the transmission of credentials and identity between this
    # program and iTunes U. Remove this code after initial
    # testing to instead receive the destination page requested.

    # uncomment the line below to access debug information from the 
    # iTunes U server.
    # $siteURL .= $debugSuffix;

    # Ready this data for transfer, the order must be correct!
    my $identity = getIdentityString($displayName, $emailAddress, $username, $userIdentifier);
    # turn the array of credentials into a semicolon delimited string
    my $credentials = getCredentialsString(@credentialArray);
    # time that this key is generated.  The key is valid for 90 seconds.
    my $currentTime = time;
    my $token = getAuthorizationToken($identity, $credentials, $currentTime, $sharedSecret);
        
    invokeAction($siteURL, $token)
}

sub getIdentityString()
{
    # Combine user identity information into an appropriately formatted string.
    # take the arguments passed into the function copy them to variables
    my ($displayName, $emailAddress, $username, $userIdentifier) = @_;

    # wrap the elements into the required delimiters.
    my $returnValue = sprintf('"%s" <%s> (%s) [%s]', $displayName, $emailAddress, $username, $userIdentifier);
    return $returnValue;
}

sub getCredentialsString()
{
    # 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.
    
    #make sure that at least one credential is passed in
    my $returnValue = "";
    my $credentialCount = @_;
    if ($credentialCount > 0) {
		for (my $i=0; $i < $credentialCount; $i++) {
			if ($i == 0) {
				$returnValue = sprintf('%s', $_[$i]);
			} else {
				$returnValue = sprintf('%s;%s', $returnValue, $_[$i]);
			}
		}
    } else {
    	die "credentialArray must have at least one credential";
    }
    return $returnValue;
}

sub getAuthorizationToken()
{
    # Create a buffer with which to generate the authorization token.
    my ($identity, $credentials, $expriation, $key) = @_;
    my $signature;
    my $buffer;

	# create the POST Content and sign it
	$buffer .= "credentials=" . uri_escape($credentials, "^A-Za-z0-9\-_.* ");
	$buffer .= "&identity=" . uri_escape($identity, "^A-Za-z0-9\-_.* ");
	$buffer .= "&time=" . uri_escape($expriation, "^A-Za-z0-9\-_.* ");
	# This is necessary because uri_escape does encode spaces to pluses.
	$buffer =~ s/[ ]/+/g;
	# returns a signed message that is sent to the server
	$signature = hmac_sha256_hex($buffer, $key);

    # append the signature to the POST content
    return sprintf("%s&signature=%s", $buffer, $signature);
}

sub invokeAction()
{
    # 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. 
    my ($siteURL, $token) = @_;

    # use different regex delimiters so you don't have to escape as much
    my ($hostName) = $siteURL =~ m|https://(.+?)/.*|;
    my ($actionPath) = $siteURL =~ m|https://$hostName(.*)|;

    my $connection = Net::HTTP->new(Host => $hostName) || die $@;
    $connection->write_request(POST => $actionPath, 'Content-Type' => "application/x-www-form-urlencoded; charset=UTF-8", $token);

    my($return_code, $message, %headers) = $connection->read_response_headers;
    
    print "Content-type: text/html\n\n";
    while (1) {
        my $buffer;
        my $entity_body = $connection->read_entity_body($buffer, 1024);
        die "read failed: $!" unless defined $entity_body;
        last unless $entity_body;
        print $buffer;
    }
}

main();
