Browse Source

IndieAuth updates

closes #8
pull/10/head
Aaron Parecki 1 year ago
parent
commit
7d00f3857c
No known key found for this signature in database
6 changed files with 76 additions and 51 deletions
  1. 2
    2
      composer.json
  2. 31
    27
      composer.lock
  3. 40
    19
      controllers/auth.php
  4. 1
    1
      views/layout.php
  5. 1
    1
      views/partials/footer.php
  6. 1
    1
      views/partials/header.php

+ 2
- 2
composer.json View File

@@ -3,9 +3,9 @@
"slim/slim": "2.2.*",
"saltybeagle/savant3": "dev-master",
"j4mie/idiorm": "1.4.*",
"mf2/mf2": "0.2.*",
"mf2/mf2": "0.3.*",
"indieweb/date-formatter": "0.1.*",
"indieauth/client": "0.1.*",
"indieauth/client": "0.2.*",
"mpratt/relativetime": ">=1.0",
"firebase/php-jwt": "^4.0",
"p3k/multipart": "*",

+ 31
- 27
composer.lock View File

@@ -4,8 +4,7 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file",
"This file is @generated automatically"
],
"hash": "ebaa6e4aed4c7cfa5a835cbe2b92e629",
"content-hash": "4b3b194b582b716faa00f4da8ce8859b",
"content-hash": "1d07c0c44cd10b3a4bc578895e82c03e",
"packages": [
{
"name": "barnabywalters/mf-cleaner",
@@ -45,7 +44,7 @@
}
],
"description": "Cleans up microformats2 array structures",
"time": "2014-10-06 23:11:15"
"time": "2014-10-06T23:11:15+00:00"
},
{
"name": "firebase/php-jwt",
@@ -88,28 +87,31 @@
],
"description": "A simple library to encode and decode JSON Web Tokens (JWT) in PHP. Should conform to the current spec.",
"homepage": "https://github.com/firebase/php-jwt",
"time": "2016-07-18 04:51:16"
"time": "2016-07-18T04:51:16+00:00"
},
{
"name": "indieauth/client",
"version": "0.1.13",
"version": "0.2.4",
"source": {
"type": "git",
"url": "https://github.com/indieweb/indieauth-client-php.git",
"reference": "d438bb03db15b4ccc6c63228be16de7870b6ab99"
"reference": "2a7f8186085d06f0371a0199e103e10729782aea"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/indieweb/indieauth-client-php/zipball/d438bb03db15b4ccc6c63228be16de7870b6ab99",
"reference": "d438bb03db15b4ccc6c63228be16de7870b6ab99",
"url": "https://api.github.com/repos/indieweb/indieauth-client-php/zipball/2a7f8186085d06f0371a0199e103e10729782aea",
"reference": "2a7f8186085d06f0371a0199e103e10729782aea",
"shasum": ""
},
"require": {
"barnabywalters/mf-cleaner": "0.*",
"indieweb/link-rel-parser": "0.1.1",
"mf2/mf2": "0.2.*",
"indieweb/link-rel-parser": "0.1.*",
"mf2/mf2": "~0.3",
"php": ">5.3.0"
},
"require-dev": {
"phpunit/phpunit": "4.8.*"
},
"type": "library",
"autoload": {
"psr-0": {
@@ -127,7 +129,7 @@
}
],
"description": "IndieAuth Client Library",
"time": "2016-02-08 23:56:31"
"time": "2017-11-23T17:22:16+00:00"
},
{
"name": "indieweb/date-formatter",
@@ -170,7 +172,7 @@
"microformats",
"microformats2"
],
"time": "2015-10-28 00:32:39"
"time": "2015-10-28T00:32:39+00:00"
},
{
"name": "indieweb/link-rel-parser",
@@ -216,7 +218,7 @@
"indieweb",
"microformats2"
],
"time": "2013-12-23 00:14:58"
"time": "2013-12-23T00:14:58+00:00"
},
{
"name": "j4mie/idiorm",
@@ -274,27 +276,29 @@
"orm",
"query builder"
],
"time": "2013-12-12 10:25:27"
"time": "2013-12-12T10:25:27+00:00"
},
{
"name": "mf2/mf2",
"version": "v0.2.12",
"version": "v0.3.2",
"source": {
"type": "git",
"url": "https://github.com/indieweb/php-mf2.git",
"reference": "6701504876d6c9242eb310b35f41d40d9785ab4e"
"reference": "dc0d90d4ee30864bcf37cd3a8fc8db94f9134cc4"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/indieweb/php-mf2/zipball/6701504876d6c9242eb310b35f41d40d9785ab4e",
"reference": "6701504876d6c9242eb310b35f41d40d9785ab4e",
"url": "https://api.github.com/repos/indieweb/php-mf2/zipball/dc0d90d4ee30864bcf37cd3a8fc8db94f9134cc4",
"reference": "dc0d90d4ee30864bcf37cd3a8fc8db94f9134cc4",
"shasum": ""
},
"require": {
"php": ">=5.3.0"
"php": ">=5.4.0"
},
"require-dev": {
"phpunit/phpunit": "3.7.*"
"mf2/tests": "@dev",
"phpdocumentor/phpdocumentor": "v2.8.4",
"phpunit/phpunit": "4.8.*"
},
"suggest": {
"barnabywalters/mf-cleaner": "To more easily handle the canonical data php-mf2 gives you"
@@ -311,7 +315,7 @@
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
"CC0"
],
"authors": [
{
@@ -327,7 +331,7 @@
"parser",
"semantic"
],
"time": "2015-07-12 14:10:01"
"time": "2017-05-27T15:27:47+00:00"
},
{
"name": "minicodemonkey/amazon-alexa-php",
@@ -366,7 +370,7 @@
}
],
"description": "Amazon Alexa interface for PHP",
"time": "2015-11-29 21:50:59"
"time": "2015-11-29T21:50:59+00:00"
},
{
"name": "mpratt/relativetime",
@@ -414,7 +418,7 @@
"time",
"time-ago"
],
"time": "2015-12-24 12:43:04"
"time": "2015-12-24T12:43:04+00:00"
},
{
"name": "p3k/multipart",
@@ -450,7 +454,7 @@
}
],
"description": "Multipart Encoding Library",
"time": "2015-07-16 19:28:02"
"time": "2015-07-16T19:28:02+00:00"
},
{
"name": "saltybeagle/savant3",
@@ -485,7 +489,7 @@
}
],
"description": "Savant3 template engine",
"time": "2014-01-07 17:10:32"
"time": "2014-01-07T17:10:32+00:00"
},
{
"name": "slim/slim",
@@ -528,7 +532,7 @@
"rest",
"router"
],
"time": "2012-12-13 02:15:50"
"time": "2012-12-13T02:15:50+00:00"
}
],
"packages-dev": [],

+ 40
- 19
controllers/auth.php View File

@@ -102,6 +102,8 @@ $app->get('/auth/start', function() use($app) {
return;
}

$_SESSION['attempted_me'] = $me;

$authorizationEndpoint = IndieAuth\Client::discoverAuthorizationEndpoint($me);
$tokenEndpoint = IndieAuth\Client::discoverTokenEndpoint($me);
$micropubEndpoint = IndieAuth\Client::discoverMicropubEndpoint($me);
@@ -124,6 +126,9 @@ $app->get('/auth/start', function() use($app) {
if($tokenEndpoint && $micropubEndpoint && $authorizationEndpoint) {
$scope = 'create';
$authorizationURL = IndieAuth\Client::buildAuthorizationURL($authorizationEndpoint, $me, buildRedirectURI(), clientID($pebble), $state, $scope);
$_SESSION['authorization_endpoint'] = $authorizationEndpoint;
$_SESSION['micropub_endpoint'] = $micropubEndpoint;
$_SESSION['token_endpoint'] = $tokenEndpoint;
} else {
$authorizationURL = IndieAuth\Client::buildAuthorizationURL('https://indieauth.com/auth', $me, buildRedirectURI(), clientID($pebble), $state);
}
@@ -175,23 +180,16 @@ $app->get('/auth/callback', function() use($app) {
$req = $app->request();
$params = $req->params();

// Double check there is a "me" parameter
// Should only fail for really hacked up requests
if(!array_key_exists('me', $params) || !($me = normalizeMeURL($params['me']))) {
// If there is no state in the session, start the login again
if(!array_key_exists('auth_state', $_SESSION)) {
render('auth_error', array(
'title' => 'Auth Callback',
'error' => 'Invalid "me" Parameter',
'errorDescription' => 'The ID you entered, <strong>' . $params['me'] . '</strong> is not valid.'
'error' => 'Missing session state',
'errorDescription' => 'Something went wrong, please try signing in again, and make sure cookies are enabled for this domain.'
));
return;
}

// If there is no state in the session, start the login again
if(!array_key_exists('auth_state', $_SESSION)) {
$app->redirect('/auth/start?me='.urlencode($params['me']));
return;
}

if(!array_key_exists('code', $params) || trim($params['code']) == '') {
render('auth_error', array(
'title' => 'Auth Callback',
@@ -207,7 +205,7 @@ $app->get('/auth/callback', function() use($app) {
render('auth_error', array(
'title' => 'Auth Callback',
'error' => 'Missing state parameter',
'errorDescription' => 'No state parameter was provided in the request. This shouldn\'t happen. It is possible this is a malicious authorization attempt.'
'errorDescription' => 'No state parameter was provided in the request. This shouldn\'t happen. It is possible this is a malicious authorization attempt, or your authorization server failed to pass back the "state" parameter.'
));
return;
}
@@ -221,26 +219,49 @@ $app->get('/auth/callback', function() use($app) {
return;
}

if(!isset($_SESSION['attempted_me'])) {
render('auth_error', [
'title' => 'Auth Callback',
'error' => 'Missing data',
'errorDescription' => 'We forgot who was logging in. It\'s possible you took too long to finish signing in, or something got mixed up by signing in in another tab.'
]);
return;
}
$me = $_SESSION['attempted_me'];

$pebble = k($_SESSION, 'pebble');

// Now the basic sanity checks have passed. Time to start providing more helpful messages when there is an error.
// An authorization code is in the query string, and we want to exchange that for an access token at the token endpoint.

// Discover the endpoints
$authorizationEndpoint = IndieAuth\Client::discoverAuthorizationEndpoint($me);
$micropubEndpoint = IndieAuth\Client::discoverMicropubEndpoint($me);
$tokenEndpoint = IndieAuth\Client::discoverTokenEndpoint($me);
$authorizationEndpoint = isset($_SESSION['authorization_endpoint']) ? $_SESSION['authorization_endpoint'] : false;
$tokenEndpoint = isset($_SESSION['token_endpoint']) ? $_SESSION['token_endpoint'] : false;
$micropubEndpoint = isset($_SESSION['micropub_endpoint']) ? $_SESSION['micropub_endpoint'] : false;

unset($_SESSION['authorization_endpoint']);
unset($_SESSION['token_endpoint']);
unset($_SESSION['micropub_endpoint']);

$skipDebugScreen = false;

if($tokenEndpoint) {
// Exchange auth code for an access token
$token = IndieAuth\Client::getAccessToken($tokenEndpoint, $params['code'], $params['me'], buildRedirectURI(), clientID($pebble), $params['state'], true);
$token = IndieAuth\Client::getAccessToken($tokenEndpoint, $params['code'], $me, buildRedirectURI(), clientID($pebble), true);

// If a valid access token was returned, store the token info in the session and they are signed in
if(k($token['auth'], array('me','access_token','scope'))) {
// Double check that the domain of the returned "me" matches the expected
if(parse_url($token['auth']['me'], PHP_URL_HOST) != parse_url($me, PHP_URL_HOST)) {
render('auth_error', [
'title' => 'Error Signing In',
'error' => 'Invalid user',
'errorDescription' => 'The user URL that was returned in the access token did not match the domain of the user signing in.'
]);
return;
}

$_SESSION['auth'] = $token['auth'];
$_SESSION['me'] = $params['me'];
$_SESSION['me'] = $token['auth']['me'];
}

} else {
@@ -253,7 +274,7 @@ $app->get('/auth/callback', function() use($app) {
$authorizationEndpoint = 'https://indieauth.com/auth';
}

$token['auth'] = IndieAuth\Client::verifyIndieAuthCode($authorizationEndpoint, $params['code'], $params['me'], buildRedirectURI(), clientID($pebble), $params['state']);
$token['auth'] = IndieAuth\Client::verifyIndieAuthCode($authorizationEndpoint, $params['code'], $me, buildRedirectURI(), clientID($pebble));

if(k($token['auth'], 'me')) {
$token['response'] = ''; // hack becuase the verify call doesn't actually return the real response

+ 1
- 1
views/layout.php View File

@@ -60,7 +60,7 @@
<?php endif; ?>

<?php if(!property_exists($this, 'footer') || $this->footer !== false): ?>
<?= partial('partials/footer') ?>
<?= partial('partials/footer', $this) ?>
<?php endif; ?>

</div>

+ 1
- 1
views/partials/footer.php View File

@@ -14,7 +14,7 @@
<li><a href="/settings"><?= preg_replace(['/https?:\/\//','/\/$/'],'',session('me')) ?></a></li>
<li><a href="/signout">Sign Out</a></li>
<? } else if(property_exists($this, 'authorizing')) { ?>
<li class="navbar-text"><?= $this->authorizing ?></li>
<li class="navbar-text"><?= htmlspecialchars($this->authorizing) ?></li>
<? } else { ?>
<form action="/auth/start" method="get" class="navbar-form">
<input type="text" name="me" placeholder="yourdomain.com" class="form-control" />

+ 1
- 1
views/partials/header.php View File

@@ -1,4 +1,4 @@
<div class="header">
<img src="/images/teacup-logo-144.png" width="42" height="42">
Teacup
<a href="/">Teacup</a>
</div>

Loading…
Cancel
Save