Index: src/__phutil_library_map__.php =================================================================== --- src/__phutil_library_map__.php +++ src/__phutil_library_map__.php @@ -104,6 +104,7 @@ 'PhutilAuthAdapterOAuthJIRA' => 'auth/PhutilAuthAdapterOAuthJIRA.php', 'PhutilAuthAdapterOAuthTwitch' => 'auth/PhutilAuthAdapterOAuthTwitch.php', 'PhutilAuthAdapterOAuthTwitter' => 'auth/PhutilAuthAdapterOAuthTwitter.php', + 'PhutilAuthAdapterPersona' => 'auth/PhutilAuthAdapterPersona.php', 'PhutilAuthException' => 'auth/exception/PhutilAuthException.php', 'PhutilAuthUserAbortedException' => 'auth/exception/PhutilAuthUserAbortedException.php', 'PhutilBallOfPHP' => 'phage/util/PhutilBallOfPHP.php', @@ -495,6 +496,7 @@ 'PhutilAuthAdapterOAuthJIRA' => 'PhutilAuthAdapterOAuth1', 'PhutilAuthAdapterOAuthTwitch' => 'PhutilAuthAdapterOAuth', 'PhutilAuthAdapterOAuthTwitter' => 'PhutilAuthAdapterOAuth1', + 'PhutilAuthAdapterPersona' => 'PhutilAuthAdapter', 'PhutilAuthException' => 'Exception', 'PhutilAuthUserAbortedException' => 'PhutilAuthException', 'PhutilBufferedIterator' => 'Iterator', Index: src/auth/PhutilAuthAdapterPersona.php =================================================================== --- /dev/null +++ src/auth/PhutilAuthAdapterPersona.php @@ -0,0 +1,68 @@ +assertion = $assertion; + return $this; + } + + public function setAudience($audience) { + $this->audience = $audience; + return $this; + } + + public function getAdapterDomain() { + return 'verifier.login.persona.org'; + } + + public function getAdapterType() { + return 'persona'; + } + + public function getAccountEmail() { + return $this->getAccountID(); + } + + public function getAccountID() { + if ($this->accountData === null) { + $verify_uri = 'https://verifier.login.persona.org/verify'; + $data = array( + 'audience' => $this->audience, + 'assertion' => $this->assertion, + ); + + list($body) = id(new HTTPSFuture($verify_uri, json_encode($data))) + ->setMethod('POST') + ->addHeader('Content-Type', 'application/json') + ->resolvex(); + + $response = json_decode($body, true); + if (!is_array($response)) { + throw new Exception("Unexpected Persona response: {$body}"); + } + + $audience = idx($response, 'audience'); + if ($audience != $this->audience) { + throw new Exception("Mismatched Persona audience: {$audience}"); + } + + if (idx($response, 'status') !== 'okay') { + $reason = idx($response, 'reason', 'Unknown'); + throw new Exception("Persona login failed: {$reason}"); + } + + $this->accountData = $response; + } + + return idx($this->accountData, 'email'); + } + +}