summaryrefslogtreecommitdiff
path: root/Postman/Postman-Auth/PostmanYahooAuthenticationManager.php
blob: 86c35d9f1a6fb66bae7484e3255d178abfcc6902 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
<?php
if ( ! defined( 'ABSPATH' ) ) {
    exit; // Exit if accessed directly
}
if (! class_exists ( "PostmanYahooAuthenticationManager" )) {
	
	require_once 'PostmanAbstractAuthenticationManager.php';
	require_once 'PostmanStateIdMissingException.php';
	
	/**
	 * Super-simple.
	 * I should have started with Yahoo.
	 *
	 * https://developer.yahoo.com/oauth2/guide/
	 * Get a Client ID at https://developer.apps.yahoo.com/projects
	 *
	 * @author jasonhendriks
	 */
	class PostmanYahooAuthenticationManager extends PostmanAbstractAuthenticationManager implements PostmanAuthenticationManager {
		
		// This endpoint is the target of the initial request. It handles active session lookup, authenticating the user, and user consent.
		const AUTHORIZATION_URL = 'https://api.login.yahoo.com/oauth2/request_auth';
		const GET_TOKEN_URL = 'https://api.login.yahoo.com/oauth2/get_token';
		
		// The SESSION key for the OAuth Transaction Id
		const AUTH_TEMP_ID = 'OAUTH_TEMP_ID';
		const VENDOR_NAME = 'yahoo';
		
		/**
		 * Constructor
		 *
		 * Get a Client ID from https://account.live.com/developers/applications/index
		 */
		public function __construct($clientId, $clientSecret, PostmanOAuthToken $authorizationToken, $callbackUri) {
			assert ( ! empty ( $clientId ) );
			assert ( ! empty ( $clientSecret ) );
			assert ( ! empty ( $authorizationToken ) );
			assert ( ! empty ( $callbackUri ) );
			$logger = new PostmanLogger ( get_class ( $this ) );
			parent::__construct ( $logger, $clientId, $clientSecret, $authorizationToken, $callbackUri );
		}
		
		/**
		 * The authorization sequence begins when your application redirects a browser to a Google URL;
		 * the URL includes query parameters that indicate the type of access being requested.
		 *
		 * As in other scenarios, Google handles user authentication, session selection, and user consent.
		 * The result is an authorization code, which Google returns to your application in a query string.
		 *
		 * (non-PHPdoc)
		 *
		 * @see PostmanAuthenticationManager::requestVerificationCode()
		 */
		public function requestVerificationCode($transactionId) {
			$params = array (
					'response_type' => 'code',
					'redirect_uri' => urlencode ( $this->getCallbackUri () ),
					'client_id' => $this->getClientId (),
					'state' => $transactionId,
					'language' => get_locale () 
			);
			
			$authUrl = $this->getAuthorizationUrl () . '?' . build_query ( $params );
			
			$this->getLogger ()->debug ( 'Requesting verification code from Yahoo' );
			PostmanUtils::redirect ( $authUrl );
		}
		
		/**
		 * After receiving the authorization code, your application can exchange the code
		 * (along with a client ID and client secret) for an access token and, in some cases,
		 * a refresh token.
		 *
		 * (non-PHPdoc)
		 *
		 * @see PostmanAuthenticationManager::processAuthorizationGrantCode()
		 */
		public function processAuthorizationGrantCode($transactionId) {
			if (isset ( $_GET ['code'] )) {
				$code = filter_input( INPUT_GET, 'code', FILTER_SANITIZE_STRING );
				$this->getLogger ()->debug ( sprintf ( 'Found authorization code %s in request header', $code ) );
				if (isset ( $_GET ['state'] ) && $_GET ['state'] == $transactionId) {
					$this->getLogger ()->debug ( 'Found valid state in request header' );
				} else {
					$this->getLogger ()->error ( 'The grant code from Yahoo had no accompanying state and may be a forgery' );
					throw new PostmanStateIdMissingException ();
				}
				// Note: The Authorization: Basic authorization header is generated through a Base64 encoding of client_id:client_secret per RFC 2617.
				// header("Authorization: Basic " . base64_encode($username . ":" . $password);
				$headers = array (
						'Authorization' => sprintf ( "Basic %s", base64_encode ( $this->getClientId () . ':' . $this->getClientSecret () ) ) 
				);
				$postvals = array (
						'code' => $code,
						'grant_type' => 'authorization_code',
						'redirect_uri' => $this->getCallbackUri () 
				);
				$response = PostmanUtils::remotePostGetBodyOnly ( $this->getTokenUrl (), $postvals, $headers );
				$this->processResponse ( $response );
				$this->getAuthorizationToken ()->setVendorName ( self::VENDOR_NAME );
				return true;
			} else {
				$this->getLogger ()->debug ( 'Expected code in the request header but found none - user probably denied request' );
				return false;
			}
		}
		
		/**
		 * Step 5: Exchange refresh token for new access token
		 * After the access token expires, you can use the refresh token, which has a long lifetime, to get a new access token.
		 */
		public function refreshToken() {
			$this->getLogger ()->debug ( 'Refreshing Token' );
			$refreshUrl = $this->getTokenUrl ();
			$callbackUrl = $this->getCallbackUri ();
			assert ( ! empty ( $refreshUrl ) );
			assert ( ! empty ( $callbackUrl ) );
			$headers = array (
					'Authorization' => sprintf ( "Basic %s", base64_encode ( $this->getClientId () . ':' . $this->getClientSecret () ) ) 
			);
			$postvals = array (
					'redirect_uri' => $callbackUrl,
					'grant_type' => 'refresh_token',
					'refresh_token' => $this->getAuthorizationToken ()->getRefreshToken () 
			);
			$response = PostmanUtils::remotePostGetBodyOnly ( $this->getTokenUrl (), $postvals, $headers );
			$this->processResponse ( $response );
		}
		public function getAuthorizationUrl() {
			return self::AUTHORIZATION_URL;
		}
		public function getTokenUrl() {
			return self::GET_TOKEN_URL;
		}
	}
}