From fa027455156c57126be0474228f8f95c4e29a2f0 Mon Sep 17 00:00:00 2001
From: Olav Morken <olav.morken@uninett.no>
Date: Tue, 8 Feb 2011 13:51:10 +0000
Subject: [PATCH] New authentication source: authmyspace

Thanks to Brook Schofield for implementing this.

git-svn-id: https://simplesamlphp.googlecode.com/svn/trunk@2735 44740490-163a-0410-bde0-09ae8108e29a
---
 attributemap/myspace2name.php                 |  18 +++
 config-templates/authsources.php              |  22 +++
 modules/authmyspace/default-disable           |   3 +
 modules/authmyspace/docs/oauthmyspace.txt     |  25 ++++
 .../authmyspace/lib/Auth/Source/MySpace.php   | 141 ++++++++++++++++++
 modules/authmyspace/www/linkback.php          |  45 ++++++
 6 files changed, 254 insertions(+)
 create mode 100644 attributemap/myspace2name.php
 create mode 100644 modules/authmyspace/default-disable
 create mode 100644 modules/authmyspace/docs/oauthmyspace.txt
 create mode 100644 modules/authmyspace/lib/Auth/Source/MySpace.php
 create mode 100644 modules/authmyspace/www/linkback.php

diff --git a/attributemap/myspace2name.php b/attributemap/myspace2name.php
new file mode 100644
index 000000000..dbc52d4b8
--- /dev/null
+++ b/attributemap/myspace2name.php
@@ -0,0 +1,18 @@
+<?php
+$attributemap = array(
+
+	// See http://developerwiki.myspace.com/index.php?title=People_API for attributes
+
+	// Generated MySpace Attributes
+	'myspace_user'			=>	'eduPersonPrincipalName', // username OR uid @ myspace.com
+	'myspace_targetedID'		=>	'eduPersonTargetedID', // http://myspace.com!uid
+	'myspace_username'		=>	'uid', // myspace username (maybe numeric uid)
+	//'myspace_uid'			=>	'uid', // numeric myspace user id
+
+	// Attributes Returned by MySpace
+	'myspace.name.givenName'	=>	'givenName',
+	'myspace.name.familyName'	=>	'sn',
+	'myspace.displayName'		=>	'displayName',
+	//'myspace.thumbnailUrl'	=>	'jpegPhoto', // URL not image data
+	'myspace.profileUrl'		=>	'labeledURI',
+);
diff --git a/config-templates/authsources.php b/config-templates/authsources.php
index 66fd41eb2..8c870901d 100644
--- a/config-templates/authsources.php
+++ b/config-templates/authsources.php
@@ -145,6 +145,28 @@ $config = array(
 	),
 	*/
 
+	/*
+	// MySpace OAuth Authentication API.
+	// Register your application to get an API key here:
+	//  http://developer.myspace.com/
+	'myspace' => array(
+		'authmyspace:MySpace',
+		'key' => 'xxxxxxxxxxxxxxxx',
+		'secret' => 'xxxxxxxxxxxxxxxx',
+	),
+	*/
+
+	/*
+	// Windows Live ID Authentication API.
+	// Register your application to get an API key here:
+	//  https://manage.dev.live.com
+	'windowslive' => array(
+		'authwindowslive:LiveID',
+		'key' => 'xxxxxxxxxxxxxxxx',
+		'secret' => 'xxxxxxxxxxxxxxxx',
+	),
+	*/
+
 	/*
 	// Example of a LDAP authentication source.
 	'example-ldap' => array(
diff --git a/modules/authmyspace/default-disable b/modules/authmyspace/default-disable
new file mode 100644
index 000000000..fa0bd82e2
--- /dev/null
+++ b/modules/authmyspace/default-disable
@@ -0,0 +1,3 @@
+This file indicates that the default state of this module
+is disabled. To enable, create a file named enable in the
+same directory as this file.
diff --git a/modules/authmyspace/docs/oauthmyspace.txt b/modules/authmyspace/docs/oauthmyspace.txt
new file mode 100644
index 000000000..284f82842
--- /dev/null
+++ b/modules/authmyspace/docs/oauthmyspace.txt
@@ -0,0 +1,25 @@
+Using the MySpace authentication source with simpleSAMLphp
+==========================================================
+
+Remember to configure `authsources.php`, with both your Client ID and Secret key.
+
+To get an API key and a secret, register the application at:
+
+ * <http://developer.myspace.com/Modules/Apps/Pages/CreateAppAccount.aspx>
+
+Create a MySpace ID App and set the callback evaluation URL to be:
+
+ * `http://sp.example.org/`
+
+Replace `sp.example.org` with your hostname.
+
+## Testing authentication
+
+On the SimpleSAMLphp frontpage, go to the *Authentication* tab, and use the link:
+
+  * *Test configured authentication sources*
+
+Then choose the *myspace* authentication source.
+
+Expected behaviour would then be that you are sent to MySpace, and asked to login.
+There is no consent screen for attribute release.
diff --git a/modules/authmyspace/lib/Auth/Source/MySpace.php b/modules/authmyspace/lib/Auth/Source/MySpace.php
new file mode 100644
index 000000000..6304762b9
--- /dev/null
+++ b/modules/authmyspace/lib/Auth/Source/MySpace.php
@@ -0,0 +1,141 @@
+<?php
+
+require_once(dirname(dirname(dirname(dirname(dirname(__FILE__))))) . '/oauth/libextinc/OAuth.php');
+
+/**
+ * Authenticate using MySpace.
+ *
+ * @author Brook Schofield, TERENA.
+ * @package simpleSAMLphp
+ * @version $Id$
+ */
+class sspmod_authmyspace_Auth_Source_MySpace extends SimpleSAML_Auth_Source {
+
+	/**
+	 * The string used to identify our states.
+	 */
+	const STAGE_INIT = 'authmyspace:init';
+
+	/**
+	 * The key of the AuthId field in the state.
+	 */
+	const AUTHID = 'authmyspace:AuthId';
+
+	private $key;
+	private $secret;
+
+
+	/**
+	 * Constructor for this authentication source.
+	 *
+	 * @param array $info  Information about this authentication source.
+	 * @param array $config  Configuration.
+	 */
+	public function __construct($info, $config) {
+		assert('is_array($info)');
+		assert('is_array($config)');
+
+		/* Call the parent constructor first, as required by the interface. */
+		parent::__construct($info, $config);
+
+		if (!array_key_exists('key', $config))
+			throw new Exception('MySpace authentication source is not properly configured: missing [key]');
+
+		$this->key = $config['key'];
+
+		if (!array_key_exists('secret', $config))
+			throw new Exception('MySpace authentication source is not properly configured: missing [secret]');
+
+		$this->secret = $config['secret'];
+	}
+
+
+	/**
+	 * Log-in using MySpace platform
+	 *
+	 * @param array &$state  Information about the current authentication.
+	 */
+	public function authenticate(&$state) {
+		assert('is_array($state)');
+
+		/* We are going to need the authId in order to retrieve this authentication source later. */
+		$state[self::AUTHID] = $this->authId;
+
+		$consumer = new sspmod_oauth_Consumer($this->key, $this->secret);
+
+		// Get the request token
+		$requestToken = $consumer->getRequestToken('http://api.myspace.com/request_token');
+		SimpleSAML_Logger::debug("Got a request token from the OAuth service provider [" .
+			$requestToken->key . "] with the secret [" . $requestToken->secret . "]");
+
+		$state['authmyspace:requestToken'] = $requestToken;
+
+		$stateID = SimpleSAML_Auth_State::saveState($state, self::STAGE_INIT);
+		SimpleSAML_Logger::debug('authmyspace auth state id = ' . $stateID);
+
+		// Authorize the request token
+		$consumer->getAuthorizeRequest('http://api.myspace.com/authorize', $requestToken, TRUE, SimpleSAML_Module::getModuleUrl('authmyspace') . '/linkback.php?stateid=' . $stateID);
+
+	}
+
+
+
+	public function finalStep(&$state) {
+
+		$requestToken = $state['authmyspace:requestToken'];
+
+		$consumer = new sspmod_oauth_Consumer($this->key, $this->secret);
+
+		SimpleSAML_Logger::debug("oauth: Using this request token [" .
+			$requestToken->key . "] with the secret [" . $requestToken->secret . "]");
+
+		// Replace the request token with an access token
+		$accessToken = $consumer->getAccessToken('http://api.myspace.com/access_token', $requestToken);
+		SimpleSAML_Logger::debug("Got an access token from the OAuth service provider [" .
+			$accessToken->key . "] with the secret [" . $accessToken->secret . "]");
+
+		// API depricated on 20th September 2010
+		//$userdata = $consumer->getUserInfo('http://api.myspace.com/v1/user.json', $accessToken);
+
+		// People API -  http://developerwiki.myspace.com/index.php?title=People_API
+		$userdata = $consumer->getUserInfo('http://api.myspace.com/1.0/people/@me/@self?fields=@all', $accessToken);
+
+		$attributes = array();
+
+		if (is_array($userdata['person'])) {
+			foreach($userdata['person'] AS $key => $value) {
+				if (is_string($value) || is_int($value))
+					$attributes['myspace.' . $key] = array((string)$value);
+
+				if (is_array($value)) {
+					foreach($value AS $key2 => $value2) {
+						if (is_string($value2) || is_int($value2))
+							$attributes['myspace.' . $key . '.' . $key2] = array((string)$value2);
+					}
+				}
+			}
+
+			if (array_key_exists('id', $userdata['person']) ) {
+
+				// person-id in the format of myspace.com.person.1234567890
+				if (preg_match('/(\d+)$/',$userdata['person']['id'],$matches)) {
+					$attributes['myspace_targetedID'] = array('http://myspace.com!' . $matches[1]);
+					$attributes['myspace_uid'] = array($matches[1]);
+					$attributes['myspace_user'] = array($matches[1] . '@myspace.com');
+				}
+			}
+
+			// profileUrl in the format http://www.myspace.com/username
+			if (array_key_exists('profileUrl', $userdata['person']) ) {
+				if (preg_match('@/([^/]+)$@',$userdata['person']['profileUrl'],$matches)) {
+					$attributes['myspace_username'] = array($matches[1]);
+					$attributes['myspace_user'] = array($matches[1] . '@myspace.com');
+				}
+			}
+		}
+
+		SimpleSAML_Logger::debug('MySpace Returned Attributes: '. implode(", ",array_keys($attributes)));
+
+		$state['Attributes'] = $attributes;
+	}
+}
diff --git a/modules/authmyspace/www/linkback.php b/modules/authmyspace/www/linkback.php
new file mode 100644
index 000000000..cc20f8b8f
--- /dev/null
+++ b/modules/authmyspace/www/linkback.php
@@ -0,0 +1,45 @@
+<?php
+
+/**
+ * Handle linkback() response from MySpace.
+ */
+
+if (array_key_exists('stateid', $_REQUEST)) {
+	$stateId = $_REQUEST['stateid'];
+} else {
+	throw new Exception('State Lost - not returned by MySpace Auth');
+}
+
+$state = SimpleSAML_Auth_State::loadState($stateId, sspmod_authmyspace_Auth_Source_MySpace::STAGE_INIT);
+
+if (array_key_exists('oauth_problem', $_REQUEST)) {
+	// oauth_problem of 'user_refused' means user chose not to login with MySpace
+	if (strcmp($_REQUEST['oauth_problem'],'user_refused') == 0) {
+		$e = new SimpleSAML_Error_UserAborted('User aborted authentication.');
+		SimpleSAML_Auth_State::throwException($state, $e);
+	}
+
+	// Error
+	$e = new SimpleSAML_Error_Error('Authentication failed: ' . $_REQUEST['oauth_problem']);
+	SimpleSAML_Auth_State::throwException($state, $e);
+}
+
+if (array_key_exists('oauth_verifier', $_REQUEST)) {
+	$state['authmyspace:oauth_verifier'] = $_REQUEST['oauth_verifier'];
+} else {
+	throw new Exception('OAuth verifier not returned.');;
+}
+
+/* Find authentication source. */
+assert('array_key_exists(sspmod_authmyspace_Auth_Source_MySpace::AUTHID, $state)');
+$sourceId = $state[sspmod_authmyspace_Auth_Source_MySpace::AUTHID];
+
+$source = SimpleSAML_Auth_Source::getById($sourceId);
+if ($source === NULL) {
+	throw new Exception('Could not find authentication source with id ' . $sourceId);
+}
+
+$source->finalStep($state);
+
+SimpleSAML_Auth_Source::completeAuth($state);
+
-- 
GitLab