Compare commits
No commits in common. "master" and "v1.4.0" have entirely different histories.
323 changed files with 16547 additions and 5563 deletions
6
.gitignore
vendored
6
.gitignore
vendored
|
@ -1 +1,5 @@
|
||||||
*~
|
nbproject/
|
||||||
|
.idea/
|
||||||
|
completer.hist
|
||||||
|
feed/
|
||||||
|
node_modules/
|
||||||
|
|
|
@ -1,11 +0,0 @@
|
||||||
image: php:7.0
|
|
||||||
|
|
||||||
before_script:
|
|
||||||
- bash ci/docker_install.sh > /dev/null
|
|
||||||
|
|
||||||
stages:
|
|
||||||
- test
|
|
||||||
|
|
||||||
test:
|
|
||||||
script:
|
|
||||||
- phpunit tests/
|
|
30
CHANGELOG.md
30
CHANGELOG.md
|
@ -4,38 +4,8 @@
|
||||||
- [B] = beta release
|
- [B] = beta release
|
||||||
- [D] = development release
|
- [D] = development release
|
||||||
|
|
||||||
|
|
||||||
- [S] release are always compared to the previous [S] release.
|
- [S] release are always compared to the previous [S] release.
|
||||||
|
|
||||||
## Version 1.5.0 (2016-08-03) [S]
|
|
||||||
|
|
||||||
- **[FEATURE]** Ability to only show post excerpts on overview pages
|
|
||||||
- **[FIX]** Fixed twitter username not specified in connfig.yaml
|
|
||||||
- **[FIX]** Fixed wrong OpenGraph meta tags
|
|
||||||
- **[CODE]** Further improved code style
|
|
||||||
- **[CODE]** Added unit tests for Config.php and ArticleGenerator.php
|
|
||||||
- **[NOTE]** If you have own language file, please update them. See also the upgrade guide
|
|
||||||
|
|
||||||
## Version 1.4.4 (2016-06-03) [S]
|
|
||||||
- **[FIX]** Error when trying to create a feed
|
|
||||||
|
|
||||||
## Version 1.4.3 (2016-05-21) [S]
|
|
||||||
- **[FIX]** Missing space in drawer between "Blogs on" and blogname
|
|
||||||
- **[FIX]** Background layer was not removed if drawer was closed
|
|
||||||
- **[FEATURE]** nextDESIGN theme added to delivered themes
|
|
||||||
- **[NOTE]** The update script to 1.4.3 works with 1.4.0, 1.4.1 and 1.4.2
|
|
||||||
|
|
||||||
## Version 1.4.2 (2016-05-18) [S]
|
|
||||||
- [FIX]: Password verification not implemented in RCC login page
|
|
||||||
|
|
||||||
## Version 1.4.1 (2016-05-18) [S]
|
|
||||||
- Switch to HTTP Basic Auth for the RCC API
|
|
||||||
- Store password as hash
|
|
||||||
- Require SSL for using the RCC and the RCC API
|
|
||||||
- [FIX] Drawer "Go back" does not work
|
|
||||||
- [FIX] Missing nodejs dependencies
|
|
||||||
- [FIX] Disqus not completly migrated to new config
|
|
||||||
|
|
||||||
## Version 1.4.0 (2016-05-07) [S]
|
## Version 1.4.0 (2016-05-07) [S]
|
||||||
|
|
||||||
- Fix: Feeds contain no text
|
- Fix: Feeds contain no text
|
||||||
|
|
38
README.md
38
README.md
|
@ -1,20 +1,18 @@
|
||||||
# Rangitaki PHP blogging engine
|
# Rangitaki PHP blogging engine
|
||||||
|
|
||||||
[![Join the chat at https://gitter.im/rangitaki/rangitaki](https://badges.gitter.im/canax/view.svg)](https://gitter.im/rangitaki/view?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
|
|
||||||
|
|
||||||
Rangitaki is a simple to use and easy to configure blogging engine, written in PHP and it has absolutely no database dependencies.
|
Rangitaki is a simple to use and easy to configure blogging engine, written in PHP and it has absolutely no database dependencies.
|
||||||
|
|
||||||
Tested with PHP version 5.5 until 7.0.
|
Tested with PHP version 5.5 until 7.0.
|
||||||
|
|
||||||
![Rangitaki](https://gitlab.com/mmk2410/rangitaki/raw/master/feature-graphic.png)
|
![Rangitaki](https://marcel-kapfer.de/blog/media/with-name.png)
|
||||||
|
|
||||||
[Wiki](https://gitlab.com/mmk2410/rangitaki/wikis/home)
|
[Website](https://marcel-kapfer.de/rangitaki)
|
||||||
|
|
||||||
[About](https://gitlab.com/mmk2410/rangitaki/wikis/about)
|
[About](https://marcel-kapfer.de/rangitaki/about)
|
||||||
|
|
||||||
[Documentation](https://gitlab.com/mmk2410/rangitaki/wikis/docs)
|
[Documentation](https://marcel-kapfer.de/rangitaki/docs)
|
||||||
|
|
||||||
[Quick Starting Guide](https://gitlab.com/mmk2410/rangitaki/wikis/docs/quickstart)
|
[Quick Starting Guide](https://marcel-kapfer.de/rangitaki/docs/quick)
|
||||||
|
|
||||||
## What is it?
|
## What is it?
|
||||||
|
|
||||||
|
@ -40,14 +38,14 @@ My goal for Rangitaki was (and still is) to create a blogging engine without dat
|
||||||
- JavaScript Extension Support
|
- JavaScript Extension Support
|
||||||
- Pagination support
|
- Pagination support
|
||||||
- Atom feed generation
|
- Atom feed generation
|
||||||
- Rangitaki Control Center (RCC; optional, read the [RCC Documentation](https://gitlab.com/mmk2410/rangitaki/wikis/docs/rcc)
|
- Rangitaki Control Center (RCC; optional, read the [RCC Documentation](https://marcel-kapfer.de/rangitaki/docs/rcc))
|
||||||
- Have a look under 'What is that RCC?' in this readme
|
- Have a look under 'What is that RCC?' in this readme
|
||||||
|
|
||||||
## Did you say 'themes'?
|
## Did you say 'themes'?
|
||||||
|
|
||||||
Yes. Rangitaki has a theme support which makes it easy to customize your blog concerning design.
|
Yes. Rangitaki has a theme support which makes it easy to customize your blog concerning design.
|
||||||
|
|
||||||
[Read the theme guide](https://gitlab.com/mmk2410/rangitaki/wikis/docs/themes)
|
[Read the theme guide](https://marcel-kapfer.de/rangitaki/docs/themes)
|
||||||
|
|
||||||
## What is that RCC?
|
## What is that RCC?
|
||||||
|
|
||||||
|
@ -60,7 +58,16 @@ It has the following features:
|
||||||
- Media upload
|
- Media upload
|
||||||
- Atom feed generation
|
- Atom feed generation
|
||||||
|
|
||||||
[Read the RCC documentation](https://gitlab.com/mmk2410/rangitaki/wikis/docs/rcc)
|
[Read the RCC documentation](https://marcel-kapfer.de/rangitaki/docs/rcc)
|
||||||
|
|
||||||
|
## Where can I see an example?
|
||||||
|
|
||||||
|
- Official Rangitaki blog [marcel-kapfer.de/rangitaki/blog](https://marcel-kapfer.de/rangitaki/blog)
|
||||||
|
|
||||||
|
- My personal blog
|
||||||
|
[marcel-kapfer.de/blog](https://marcel-kapfer.de/blog)
|
||||||
|
|
||||||
|
Would you like to see your Rangitaki blog here? Write me a message at [marcelmichaelkapfer@yahoo.co.nz](mailto:marcelmichaelkapfer@yahoo.co.nz)
|
||||||
|
|
||||||
## Used Libraries
|
## Used Libraries
|
||||||
|
|
||||||
|
@ -71,7 +78,8 @@ It has the following features:
|
||||||
|
|
||||||
## Issues, Requests, etc.
|
## Issues, Requests, etc.
|
||||||
|
|
||||||
For bug reports, feature requests and all other questions or recommendations feel free to create an issue here at [GitLab](https://gitlab.com/mmk2410/rangitaki/issues).
|
For bug reports, feature requests and all other stuff use
|
||||||
|
[phab.mmk2410.org/maniphest](https://phab.mmk2410.org/maniphest).
|
||||||
|
|
||||||
## Code
|
## Code
|
||||||
|
|
||||||
|
@ -79,13 +87,13 @@ For bug reports, feature requests and all other questions or recommendations fee
|
||||||
2. Create your feature branch (`git checkout -b my-new-feature`)
|
2. Create your feature branch (`git checkout -b my-new-feature`)
|
||||||
3. Commit your changes (`git commit -am 'Add some feature'`)
|
3. Commit your changes (`git commit -am 'Add some feature'`)
|
||||||
4. Push to the branch (`git push origin my-new-feature`)
|
4. Push to the branch (`git push origin my-new-feature`)
|
||||||
5. Create new merge request
|
5. Create New Pull Request
|
||||||
|
|
||||||
Read also the [contributing documentation](https://gitlab.com/mmk2410/rangitaki/wikis/docs/contribute)
|
Read also the [contributing documentation](https://marcel-kapfer.de/rangitaki/docs/contrib)
|
||||||
|
|
||||||
## Social
|
## Social
|
||||||
|
|
||||||
You can follow me on Twitter or subscribe my blog to receive news about Rangitaki.
|
You can follow my personal Twitter and Google+ account to receive news about the Rangitaki blogging engine.
|
||||||
|
|
||||||
- [Twitter @mmk2410](https://twitter.com/mmk2410)
|
- [Twitter @mmk2410](https://twitter.com/mmk2410)
|
||||||
- [Blog mmk2410.org](https://mmk2410.org/), you can view the current posts about Rangitaki on [this page](https://mmk2410.org/tag/rangitaki/).
|
- [Google+ +MarcelKapfer](https://plus.google.com/+MarcelMichaelKapfer/posts)
|
||||||
|
|
|
@ -39,8 +39,6 @@ $themes = getDir('./themes');
|
||||||
$yaml["design"]["theme"] = get("Which theme would you like to use? (" . $themes . ")", $yaml["design"]["theme"], "material-light");
|
$yaml["design"]["theme"] = get("Which theme would you like to use? (" . $themes . ")", $yaml["design"]["theme"], "material-light");
|
||||||
$yaml["design"]["pagination"] =
|
$yaml["design"]["pagination"] =
|
||||||
get("Which posts should be displayed on one page (0 to disable)", $yaml["design"]["pagination"], "0");
|
get("Which posts should be displayed on one page (0 to disable)", $yaml["design"]["pagination"], "0");
|
||||||
$yaml["design"]["excerpt"] =
|
|
||||||
getBool("Should be overview pages only show a excerpt of the full posts? (on/off)", $yaml["design"]["excerpt"], "off");
|
|
||||||
$yaml["design"]["favicon"] = get("URL to your favicon", $yaml["design"]["favicon"], "https://example.com/fav.ico");
|
$yaml["design"]["favicon"] = get("URL to your favicon", $yaml["design"]["favicon"], "https://example.com/fav.ico");
|
||||||
|
|
||||||
// rcc
|
// rcc
|
||||||
|
@ -51,9 +49,6 @@ $yaml["rcc"]["api"] = "off";
|
||||||
$langs = getDir('./lang');
|
$langs = getDir('./lang');
|
||||||
$yaml["language"] = get("Choose a language (" . $langs . ")", $yaml["language"], "en");
|
$yaml["language"] = get("Choose a language (" . $langs . ")", $yaml["language"], "en");
|
||||||
|
|
||||||
// social media
|
|
||||||
$yaml["social"]["twitter"] = get("Your Twitter username:", $yaml["social"]["twitter"], "");
|
|
||||||
|
|
||||||
$config->writeConfig($yaml);
|
$config->writeConfig($yaml);
|
||||||
|
|
||||||
function get($question, $value, $default)
|
function get($question, $value, $default)
|
||||||
|
|
|
@ -23,14 +23,8 @@ if ($password == "") {
|
||||||
exit();
|
exit();
|
||||||
}
|
}
|
||||||
|
|
||||||
$options = [
|
|
||||||
'cost' => 12
|
|
||||||
];
|
|
||||||
|
|
||||||
$password = password_hash($password, PASSWORD_BCRYPT, $options);
|
|
||||||
|
|
||||||
$username = '$username = "' . $username . '";';
|
$username = '$username = "' . $username . '";';
|
||||||
$password = '$password = \'' . $password . '\';';
|
$password = '$password = "' . $password . '";';
|
||||||
|
|
||||||
$file = '<?php' . "\n" . $username . "\n" . $password . "\n";
|
$file = '<?php' . "\n" . $username . "\n" . $password . "\n";
|
||||||
|
|
||||||
|
|
|
@ -1,2 +0,0 @@
|
||||||
%TITLE: Docs
|
|
||||||
%URL: https://mmk2410.org/rangitaki/docs/
|
|
|
@ -2,8 +2,13 @@
|
||||||
|
|
||||||
This is the Blog of the Blog Engine **Rangitaki**
|
This is the Blog of the Blog Engine **Rangitaki**
|
||||||
|
|
||||||
Rangitaki is based on PHP and Markdown. It is easy to install and to configure.
|
Rangitaki is based on PHP, XML and Markdown. It is easy to install and to configure.
|
||||||
|
|
||||||
The latest version of Rangitaki is 1.4.3.
|
The latest Version of the 0.2 series is **0.2.2**
|
||||||
|
|
||||||
You can find the source code on [GitLab](https://gitlab.com/mmk2410/rangitaki).
|
The latest Version of the development stream isn' ready yet.
|
||||||
|
|
||||||
|
|
||||||
|
** !IMPORTANT! Please read [this](index.php?article=About-the-Future-of-pBlog) for more information about the different versions of pBlog.**
|
||||||
|
|
||||||
|
You can find the source code on [GitHub](https://github.com/mmk2410/Rangitaki).
|
|
@ -1,15 +0,0 @@
|
||||||
#!/bin/bash
|
|
||||||
|
|
||||||
# Only install dependencies for Docker
|
|
||||||
[[ ! -e /.dockerenv ]] && [[ ! -e /.dockerinit ]] && exit 0
|
|
||||||
|
|
||||||
set -xe
|
|
||||||
|
|
||||||
# Install git
|
|
||||||
apt-get update -yqq
|
|
||||||
apt-get install git -yqq
|
|
||||||
|
|
||||||
# Install phpunit
|
|
||||||
curl -o /usr/local/bin/phpunit https://phar.phpunit.de/phpunit.phar
|
|
||||||
chmod +x /usr/local/bin/phpunit
|
|
||||||
|
|
144
composer.lock
generated
144
composer.lock
generated
|
@ -4,8 +4,58 @@
|
||||||
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file",
|
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file",
|
||||||
"This file is @generated automatically"
|
"This file is @generated automatically"
|
||||||
],
|
],
|
||||||
"content-hash": "ccdcfdb56ed68253e2388261fbb6d1b3",
|
"hash": "bf0772b9501ce6231c06bfbcdb671d1d",
|
||||||
|
"content-hash": "49b3f5550e60b62ffeb5306a75a87d97",
|
||||||
"packages": [
|
"packages": [
|
||||||
|
{
|
||||||
|
"name": "bshaffer/oauth2-server-php",
|
||||||
|
"version": "v1.8.0",
|
||||||
|
"source": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "https://github.com/bshaffer/oauth2-server-php.git",
|
||||||
|
"reference": "058c98f73209f9c49495e1799d32c035196fe8b8"
|
||||||
|
},
|
||||||
|
"dist": {
|
||||||
|
"type": "zip",
|
||||||
|
"url": "https://api.github.com/repos/bshaffer/oauth2-server-php/zipball/058c98f73209f9c49495e1799d32c035196fe8b8",
|
||||||
|
"reference": "058c98f73209f9c49495e1799d32c035196fe8b8",
|
||||||
|
"shasum": ""
|
||||||
|
},
|
||||||
|
"require": {
|
||||||
|
"php": ">=5.3.9"
|
||||||
|
},
|
||||||
|
"suggest": {
|
||||||
|
"aws/aws-sdk-php": "~2.8 is required to use the DynamoDB storage engine",
|
||||||
|
"firebase/php-jwt": "~2.2 is required to use JWT features",
|
||||||
|
"predis/predis": "Required to use the Redis storage engine",
|
||||||
|
"thobbs/phpcassa": "Required to use the Cassandra storage engine"
|
||||||
|
},
|
||||||
|
"type": "library",
|
||||||
|
"autoload": {
|
||||||
|
"psr-0": {
|
||||||
|
"OAuth2": "src/"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"notification-url": "https://packagist.org/downloads/",
|
||||||
|
"license": [
|
||||||
|
"MIT"
|
||||||
|
],
|
||||||
|
"authors": [
|
||||||
|
{
|
||||||
|
"name": "Brent Shaffer",
|
||||||
|
"email": "bshafs@gmail.com",
|
||||||
|
"homepage": "http://brentertainment.com"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"description": "OAuth2 Server for PHP",
|
||||||
|
"homepage": "http://github.com/bshaffer/oauth2-server-php",
|
||||||
|
"keywords": [
|
||||||
|
"auth",
|
||||||
|
"oauth",
|
||||||
|
"oauth2"
|
||||||
|
],
|
||||||
|
"time": "2015-09-18 18:05:10"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"name": "codeguy/upload",
|
"name": "codeguy/upload",
|
||||||
"version": "1.3.2",
|
"version": "1.3.2",
|
||||||
|
@ -51,7 +101,7 @@
|
||||||
"upload",
|
"upload",
|
||||||
"validation"
|
"validation"
|
||||||
],
|
],
|
||||||
"time": "2013-07-07T17:01:41+00:00"
|
"time": "2013-07-07 17:01:41"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "container-interop/container-interop",
|
"name": "container-interop/container-interop",
|
||||||
|
@ -78,25 +128,22 @@
|
||||||
"MIT"
|
"MIT"
|
||||||
],
|
],
|
||||||
"description": "Promoting the interoperability of container objects (DIC, SL, etc.)",
|
"description": "Promoting the interoperability of container objects (DIC, SL, etc.)",
|
||||||
"time": "2014-12-30T15:22:37+00:00"
|
"time": "2014-12-30 15:22:37"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "erusev/parsedown",
|
"name": "erusev/parsedown",
|
||||||
"version": "1.6.1",
|
"version": "1.6.0",
|
||||||
"source": {
|
"source": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "https://github.com/erusev/parsedown.git",
|
"url": "https://github.com/erusev/parsedown.git",
|
||||||
"reference": "20ff8bbb57205368b4b42d094642a3e52dac85fb"
|
"reference": "3ebbd730b5c2cf5ce78bc1bf64071407fc6674b7"
|
||||||
},
|
},
|
||||||
"dist": {
|
"dist": {
|
||||||
"type": "zip",
|
"type": "zip",
|
||||||
"url": "https://api.github.com/repos/erusev/parsedown/zipball/20ff8bbb57205368b4b42d094642a3e52dac85fb",
|
"url": "https://api.github.com/repos/erusev/parsedown/zipball/3ebbd730b5c2cf5ce78bc1bf64071407fc6674b7",
|
||||||
"reference": "20ff8bbb57205368b4b42d094642a3e52dac85fb",
|
"reference": "3ebbd730b5c2cf5ce78bc1bf64071407fc6674b7",
|
||||||
"shasum": ""
|
"shasum": ""
|
||||||
},
|
},
|
||||||
"require": {
|
|
||||||
"php": ">=5.3.0"
|
|
||||||
},
|
|
||||||
"type": "library",
|
"type": "library",
|
||||||
"autoload": {
|
"autoload": {
|
||||||
"psr-0": {
|
"psr-0": {
|
||||||
|
@ -120,20 +167,20 @@
|
||||||
"markdown",
|
"markdown",
|
||||||
"parser"
|
"parser"
|
||||||
],
|
],
|
||||||
"time": "2016-11-02T15:56:58+00:00"
|
"time": "2015-10-04 16:44:32"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "fguillot/picofeed",
|
"name": "fguillot/picofeed",
|
||||||
"version": "v0.1.28",
|
"version": "v0.1.23",
|
||||||
"source": {
|
"source": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "https://github.com/fguillot/picoFeed.git",
|
"url": "https://github.com/fguillot/picoFeed.git",
|
||||||
"reference": "9da506c308bcb40b6fc630f9123466028c03170b"
|
"reference": "a7c3d420c239fe9ffc39b0d06b6e57db39ce3797"
|
||||||
},
|
},
|
||||||
"dist": {
|
"dist": {
|
||||||
"type": "zip",
|
"type": "zip",
|
||||||
"url": "https://api.github.com/repos/fguillot/picoFeed/zipball/9da506c308bcb40b6fc630f9123466028c03170b",
|
"url": "https://api.github.com/repos/fguillot/picoFeed/zipball/a7c3d420c239fe9ffc39b0d06b6e57db39ce3797",
|
||||||
"reference": "9da506c308bcb40b6fc630f9123466028c03170b",
|
"reference": "a7c3d420c239fe9ffc39b0d06b6e57db39ce3797",
|
||||||
"shasum": ""
|
"shasum": ""
|
||||||
},
|
},
|
||||||
"require": {
|
"require": {
|
||||||
|
@ -145,11 +192,6 @@
|
||||||
"php": ">=5.3.0",
|
"php": ">=5.3.0",
|
||||||
"zendframework/zendxml": "^1.0"
|
"zendframework/zendxml": "^1.0"
|
||||||
},
|
},
|
||||||
"require-dev": {
|
|
||||||
"phpdocumentor/reflection-docblock": "2.0.4",
|
|
||||||
"phpunit/phpunit": "4.8.26",
|
|
||||||
"symfony/yaml": "2.8.7"
|
|
||||||
},
|
|
||||||
"suggest": {
|
"suggest": {
|
||||||
"ext-curl": "PicoFeed will use cURL if present"
|
"ext-curl": "PicoFeed will use cURL if present"
|
||||||
},
|
},
|
||||||
|
@ -173,20 +215,20 @@
|
||||||
],
|
],
|
||||||
"description": "Modern library to handle RSS/Atom feeds",
|
"description": "Modern library to handle RSS/Atom feeds",
|
||||||
"homepage": "https://github.com/fguillot/picoFeed",
|
"homepage": "https://github.com/fguillot/picoFeed",
|
||||||
"time": "2016-12-29T00:06:41+00:00"
|
"time": "2016-04-17 22:31:55"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "nikic/fast-route",
|
"name": "nikic/fast-route",
|
||||||
"version": "v1.1.0",
|
"version": "v0.6.0",
|
||||||
"source": {
|
"source": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "https://github.com/nikic/FastRoute.git",
|
"url": "https://github.com/nikic/FastRoute.git",
|
||||||
"reference": "f3dcf5130e634b6123d40727d612ec6aa4f61fb3"
|
"reference": "31fa86924556b80735f98b294a7ffdfb26789f22"
|
||||||
},
|
},
|
||||||
"dist": {
|
"dist": {
|
||||||
"type": "zip",
|
"type": "zip",
|
||||||
"url": "https://api.github.com/repos/nikic/FastRoute/zipball/f3dcf5130e634b6123d40727d612ec6aa4f61fb3",
|
"url": "https://api.github.com/repos/nikic/FastRoute/zipball/31fa86924556b80735f98b294a7ffdfb26789f22",
|
||||||
"reference": "f3dcf5130e634b6123d40727d612ec6aa4f61fb3",
|
"reference": "31fa86924556b80735f98b294a7ffdfb26789f22",
|
||||||
"shasum": ""
|
"shasum": ""
|
||||||
},
|
},
|
||||||
"require": {
|
"require": {
|
||||||
|
@ -216,7 +258,7 @@
|
||||||
"router",
|
"router",
|
||||||
"routing"
|
"routing"
|
||||||
],
|
],
|
||||||
"time": "2016-10-20T17:36:47+00:00"
|
"time": "2015-06-18 19:15:47"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "pimple/pimple",
|
"name": "pimple/pimple",
|
||||||
|
@ -262,20 +304,20 @@
|
||||||
"container",
|
"container",
|
||||||
"dependency injection"
|
"dependency injection"
|
||||||
],
|
],
|
||||||
"time": "2015-09-11T15:10:35+00:00"
|
"time": "2015-09-11 15:10:35"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "psr/http-message",
|
"name": "psr/http-message",
|
||||||
"version": "1.0.1",
|
"version": "1.0",
|
||||||
"source": {
|
"source": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "https://github.com/php-fig/http-message.git",
|
"url": "https://github.com/php-fig/http-message.git",
|
||||||
"reference": "f6561bf28d520154e4b0ec72be95418abe6d9363"
|
"reference": "85d63699f0dbedb190bbd4b0d2b9dc707ea4c298"
|
||||||
},
|
},
|
||||||
"dist": {
|
"dist": {
|
||||||
"type": "zip",
|
"type": "zip",
|
||||||
"url": "https://api.github.com/repos/php-fig/http-message/zipball/f6561bf28d520154e4b0ec72be95418abe6d9363",
|
"url": "https://api.github.com/repos/php-fig/http-message/zipball/85d63699f0dbedb190bbd4b0d2b9dc707ea4c298",
|
||||||
"reference": "f6561bf28d520154e4b0ec72be95418abe6d9363",
|
"reference": "85d63699f0dbedb190bbd4b0d2b9dc707ea4c298",
|
||||||
"shasum": ""
|
"shasum": ""
|
||||||
},
|
},
|
||||||
"require": {
|
"require": {
|
||||||
|
@ -303,7 +345,6 @@
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"description": "Common interface for HTTP messages",
|
"description": "Common interface for HTTP messages",
|
||||||
"homepage": "https://github.com/php-fig/http-message",
|
|
||||||
"keywords": [
|
"keywords": [
|
||||||
"http",
|
"http",
|
||||||
"http-message",
|
"http-message",
|
||||||
|
@ -312,32 +353,29 @@
|
||||||
"request",
|
"request",
|
||||||
"response"
|
"response"
|
||||||
],
|
],
|
||||||
"time": "2016-08-06T14:39:51+00:00"
|
"time": "2015-05-04 20:22:00"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "slim/slim",
|
"name": "slim/slim",
|
||||||
"version": "3.7.0",
|
"version": "3.3.0",
|
||||||
"source": {
|
"source": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "https://github.com/slimphp/Slim.git",
|
"url": "https://github.com/slimphp/Slim.git",
|
||||||
"reference": "4254e40d81559e35cdf856bcbaca5f3af468b7ef"
|
"reference": "939f2e85d57508de9cff241d10091cd972f221c3"
|
||||||
},
|
},
|
||||||
"dist": {
|
"dist": {
|
||||||
"type": "zip",
|
"type": "zip",
|
||||||
"url": "https://api.github.com/repos/slimphp/Slim/zipball/4254e40d81559e35cdf856bcbaca5f3af468b7ef",
|
"url": "https://api.github.com/repos/slimphp/Slim/zipball/939f2e85d57508de9cff241d10091cd972f221c3",
|
||||||
"reference": "4254e40d81559e35cdf856bcbaca5f3af468b7ef",
|
"reference": "939f2e85d57508de9cff241d10091cd972f221c3",
|
||||||
"shasum": ""
|
"shasum": ""
|
||||||
},
|
},
|
||||||
"require": {
|
"require": {
|
||||||
"container-interop/container-interop": "^1.1",
|
"container-interop/container-interop": "^1.1",
|
||||||
"nikic/fast-route": "^1.0",
|
"nikic/fast-route": "^0.6",
|
||||||
"php": ">=5.5.0",
|
"php": ">=5.5.0",
|
||||||
"pimple/pimple": "^3.0",
|
"pimple/pimple": "^3.0",
|
||||||
"psr/http-message": "^1.0"
|
"psr/http-message": "^1.0"
|
||||||
},
|
},
|
||||||
"provide": {
|
|
||||||
"psr/http-message-implementation": "1.0"
|
|
||||||
},
|
|
||||||
"require-dev": {
|
"require-dev": {
|
||||||
"phpunit/phpunit": "^4.0",
|
"phpunit/phpunit": "^4.0",
|
||||||
"squizlabs/php_codesniffer": "^2.5"
|
"squizlabs/php_codesniffer": "^2.5"
|
||||||
|
@ -375,42 +413,36 @@
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"description": "Slim is a PHP micro framework that helps you quickly write simple yet powerful web applications and APIs",
|
"description": "Slim is a PHP micro framework that helps you quickly write simple yet powerful web applications and APIs",
|
||||||
"homepage": "https://slimframework.com",
|
"homepage": "http://slimframework.com",
|
||||||
"keywords": [
|
"keywords": [
|
||||||
"api",
|
"api",
|
||||||
"framework",
|
"framework",
|
||||||
"micro",
|
"micro",
|
||||||
"router"
|
"router"
|
||||||
],
|
],
|
||||||
"time": "2016-12-20T20:30:47+00:00"
|
"time": "2016-03-10 21:37:40"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "symfony/yaml",
|
"name": "symfony/yaml",
|
||||||
"version": "v3.2.1",
|
"version": "v3.0.4",
|
||||||
"source": {
|
"source": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "https://github.com/symfony/yaml.git",
|
"url": "https://github.com/symfony/yaml.git",
|
||||||
"reference": "a7095af4b97a0955f85c8989106c249fa649011f"
|
"reference": "0047c8366744a16de7516622c5b7355336afae96"
|
||||||
},
|
},
|
||||||
"dist": {
|
"dist": {
|
||||||
"type": "zip",
|
"type": "zip",
|
||||||
"url": "https://api.github.com/repos/symfony/yaml/zipball/a7095af4b97a0955f85c8989106c249fa649011f",
|
"url": "https://api.github.com/repos/symfony/yaml/zipball/0047c8366744a16de7516622c5b7355336afae96",
|
||||||
"reference": "a7095af4b97a0955f85c8989106c249fa649011f",
|
"reference": "0047c8366744a16de7516622c5b7355336afae96",
|
||||||
"shasum": ""
|
"shasum": ""
|
||||||
},
|
},
|
||||||
"require": {
|
"require": {
|
||||||
"php": ">=5.5.9"
|
"php": ">=5.5.9"
|
||||||
},
|
},
|
||||||
"require-dev": {
|
|
||||||
"symfony/console": "~2.8|~3.0"
|
|
||||||
},
|
|
||||||
"suggest": {
|
|
||||||
"symfony/console": "For validating YAML files using the lint command"
|
|
||||||
},
|
|
||||||
"type": "library",
|
"type": "library",
|
||||||
"extra": {
|
"extra": {
|
||||||
"branch-alias": {
|
"branch-alias": {
|
||||||
"dev-master": "3.2-dev"
|
"dev-master": "3.0-dev"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"autoload": {
|
"autoload": {
|
||||||
|
@ -437,7 +469,7 @@
|
||||||
],
|
],
|
||||||
"description": "Symfony Yaml Component",
|
"description": "Symfony Yaml Component",
|
||||||
"homepage": "https://symfony.com",
|
"homepage": "https://symfony.com",
|
||||||
"time": "2016-12-10T10:07:06+00:00"
|
"time": "2016-03-04 07:55:57"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "zendframework/zendxml",
|
"name": "zendframework/zendxml",
|
||||||
|
@ -482,7 +514,7 @@
|
||||||
"xml",
|
"xml",
|
||||||
"zf2"
|
"zf2"
|
||||||
],
|
],
|
||||||
"time": "2016-02-04T21:02:08+00:00"
|
"time": "2016-02-04 21:02:08"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"packages-dev": [],
|
"packages-dev": [],
|
||||||
|
|
|
@ -9,19 +9,15 @@ blog:
|
||||||
intro: 'on'
|
intro: 'on'
|
||||||
disqus: rangitaki
|
disqus: rangitaki
|
||||||
analytics: ''
|
analytics: ''
|
||||||
footer: "Rangitaki 2016 <a href=\"https://gitlab.com/mmk2410/rangitaki\" target=\"blank\">\n gitlab.com/mmk2410/rangitaki</a>"
|
footer: "Rangitaki 2016 <a href=\"https://github.com/mmk2410/Rangitaki\" target=\"blank\">\n github.com/mmk2410/Rangitaki</a>"
|
||||||
url: 'https://example.com/blog/'
|
url: 'https://example.com/blog/'
|
||||||
design:
|
design:
|
||||||
excerpt: "off"
|
|
||||||
fab: 'on'
|
fab: 'on'
|
||||||
drawer: 'on'
|
drawer: 'on'
|
||||||
theme: material-light
|
theme: material-light
|
||||||
pagination: 0
|
pagination: 0
|
||||||
excerpt: 'off'
|
|
||||||
favicon: 'http://example.com/res/img/favicon.png'
|
favicon: 'http://example.com/res/img/favicon.png'
|
||||||
rcc:
|
rcc:
|
||||||
rcc: 'on'
|
rcc: 'on'
|
||||||
api: 'on'
|
api: 'on'
|
||||||
language: en
|
language: en
|
||||||
social:
|
|
||||||
twitter: ''
|
|
||||||
|
|
Binary file not shown.
Before Width: | Height: | Size: 63 KiB |
60
index.php
60
index.php
|
@ -25,10 +25,7 @@ date_default_timezone_set('UTC');
|
||||||
require __DIR__ . '/vendor/autoload.php'; // loading composer libs
|
require __DIR__ . '/vendor/autoload.php'; // loading composer libs
|
||||||
|
|
||||||
require './res/php/Config.php';
|
require './res/php/Config.php';
|
||||||
require_once './res/php/BlogListGenerator.php';
|
|
||||||
|
|
||||||
use mmk2410\rbe\config\Config as Config;
|
use mmk2410\rbe\config\Config as Config;
|
||||||
use mmk2410\rbe\BlogListGenerator\BlogListGenerator as BlogListGenerator;
|
|
||||||
|
|
||||||
$configParser = new Config('config.yaml', 'vendor/autoload.php');
|
$configParser = new Config('config.yaml', 'vendor/autoload.php');
|
||||||
|
|
||||||
|
@ -36,7 +33,7 @@ $config = $configParser->getConfig();
|
||||||
|
|
||||||
require './lang/' . $config["language"] . ".php"; // Language file
|
require './lang/' . $config["language"] . ".php"; // Language file
|
||||||
require_once 'res/php/ArticleGenerator.php'; // The article generator
|
require_once 'res/php/ArticleGenerator.php'; // The article generator
|
||||||
|
require_once './res/php/BlogListGenerator.php'; // and the blog list generator
|
||||||
|
|
||||||
// Getting some variables ($_GET and $_SERVER)
|
// Getting some variables ($_GET and $_SERVER)
|
||||||
$getblog = filter_input(INPUT_GET, "blog"); // get the blog variable
|
$getblog = filter_input(INPUT_GET, "blog"); // get the blog variable
|
||||||
|
@ -117,9 +114,10 @@ $feedurl = $config["blog"]["url"] . "/feed/" . $blog . ".atom";
|
||||||
<meta property="og:url" content="<?php echo $url; ?>"/>
|
<meta property="og:url" content="<?php echo $url; ?>"/>
|
||||||
<meta property="og:image" content="<?php echo $config['design']['favicon']; ?>"/>
|
<meta property="og:image" content="<?php echo $config['design']['favicon']; ?>"/>
|
||||||
<meta property="og:description" content="<?php echo $config['blog']['description']; ?>"/>
|
<meta property="og:description" content="<?php echo $config['blog']['description']; ?>"/>
|
||||||
|
<meta property="og:locale:alternate" content="<?php echo $lang; ?>"/>
|
||||||
<!-- Twitter meta tags -->
|
<!-- Twitter meta tags -->
|
||||||
<meta name="twitter:card" content="summary"/>
|
<meta name="twitter:card" content="summary"/>
|
||||||
<meta name="twitter:site" content="<?php echo $config['social']['twitter']; ?>"/>
|
<meta name="twitter:site" content="<?php echo $twitter; ?>"/>
|
||||||
<meta name="twitter:title" content="<?php echo $hd_subblog_title; ?>"/>
|
<meta name="twitter:title" content="<?php echo $hd_subblog_title; ?>"/>
|
||||||
<meta name="twitter:description" content="<?php echo $config['blog']['description']; ?>"/>
|
<meta name="twitter:description" content="<?php echo $config['blog']['description']; ?>"/>
|
||||||
<meta name="twitter:image" content="<?php echo $config['design']['favicon']; ?>"/>
|
<meta name="twitter:image" content="<?php echo $config['design']['favicon']; ?>"/>
|
||||||
|
@ -185,7 +183,7 @@ if ($config["design"]["drawer"] == "on") {
|
||||||
echo "<section>";
|
echo "<section>";
|
||||||
// 1. Set localized string 2. Set blogtitle
|
// 1. Set localized string 2. Set blogtitle
|
||||||
echo "<div class='nav-item-static'>" .
|
echo "<div class='nav-item-static'>" .
|
||||||
$BLOGLANG['Blogs on'] . " " . $config["blog"]["title"] .
|
$BLOGLANG['Blogs on'] . $config["blog"]["title"] .
|
||||||
":</div>";
|
":</div>";
|
||||||
// iterating through the blogs/ directory
|
// iterating through the blogs/ directory
|
||||||
foreach ($blogs as $navblog) {
|
foreach ($blogs as $navblog) {
|
||||||
|
@ -195,10 +193,8 @@ if ($config["design"]["drawer"] == "on") {
|
||||||
if ($getblog == "") { // Run when on main blog
|
if ($getblog == "") { // Run when on main blog
|
||||||
if ($navblog != "main.md") { // excluding main blog
|
if ($navblog != "main.md") { // excluding main blog
|
||||||
// creating navigation item
|
// creating navigation item
|
||||||
echo BlogListGenerator::listBlog(
|
BlogListGenerator::listBlog(
|
||||||
"./blogs/",
|
"./blogs/", $navblog, $config["blog"]["title"]
|
||||||
$navblog,
|
|
||||||
$config["blog"]["title"]
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
@ -206,10 +202,8 @@ if ($config["design"]["drawer"] == "on") {
|
||||||
// -> this blog will be excluded
|
// -> this blog will be excluded
|
||||||
if ($getblog . ".md" != $navblog) {
|
if ($getblog . ".md" != $navblog) {
|
||||||
// creating navigation item
|
// creating navigation item
|
||||||
echo BlogListGenerator::listBlog(
|
BlogListGenerator::listBlog(
|
||||||
"./blogs/",
|
"./blogs/", $navblog, $blogmaintitle
|
||||||
$navblog,
|
|
||||||
$blogmaintitle
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -220,7 +214,7 @@ if ($config["design"]["drawer"] == "on") {
|
||||||
// If viewing a blog or a tag
|
// If viewing a blog or a tag
|
||||||
?>
|
?>
|
||||||
<!-- Set a back item instead of the blogs. -->
|
<!-- Set a back item instead of the blogs. -->
|
||||||
<a class="nav-item" onclick="history.go(-1);">Go back</a>
|
<a class="nav-item" onclick="goBack()">Go back</a>
|
||||||
<?php
|
<?php
|
||||||
}
|
}
|
||||||
if ($config["blog"]["home"] == "on") { // If a blog home is existend
|
if ($config["blog"]["home"] == "on") { // If a blog home is existend
|
||||||
|
@ -325,11 +319,7 @@ if ($config["design"]["drawer"] == "on") {
|
||||||
if (strlen($article) >= 3 && substr($article, -3) == ".md") {
|
if (strlen($article) >= 3 && substr($article, -3) == ".md") {
|
||||||
// generate the article
|
// generate the article
|
||||||
ArticleGenerator::newArticle(
|
ArticleGenerator::newArticle(
|
||||||
$articlesdir,
|
$articlesdir, $article, $getblog
|
||||||
$article,
|
|
||||||
$getblog,
|
|
||||||
$config["design"]["excerpt"],
|
|
||||||
$BLOGLANG["Read More"]
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -347,20 +337,12 @@ if ($config["design"]["drawer"] == "on") {
|
||||||
if ($config["design"]["pagination"]) {
|
if ($config["design"]["pagination"]) {
|
||||||
if ($posts_amount < $pag_max && $posts_amount >= $pag_min) {
|
if ($posts_amount < $pag_max && $posts_amount >= $pag_min) {
|
||||||
ArticleGenerator::newArticle(
|
ArticleGenerator::newArticle(
|
||||||
$articlesdir,
|
$articlesdir, $article, $getblog
|
||||||
$article,
|
|
||||||
$getblog,
|
|
||||||
$config["design"]["excerpt"],
|
|
||||||
$BLOGLANG["Read More"]
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
ArticleGenerator::newArticle(
|
ArticleGenerator::newArticle(
|
||||||
$articlesdir,
|
$articlesdir, $article, $getblog
|
||||||
$article,
|
|
||||||
$getblog,
|
|
||||||
$config["design"]["excerpt"],
|
|
||||||
$BLOGLANG["Read More"]
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -372,11 +354,7 @@ if ($config["design"]["drawer"] == "on") {
|
||||||
} elseif (isset($getarticle)) { // ARTICLE VIEW
|
} elseif (isset($getarticle)) { // ARTICLE VIEW
|
||||||
// generate the requested article
|
// generate the requested article
|
||||||
ArticleGenerator::newArticle(
|
ArticleGenerator::newArticle(
|
||||||
$articlesdir,
|
$articlesdir, $getarticle . ".md", $getblog
|
||||||
$getarticle . ".md",
|
|
||||||
$getblog,
|
|
||||||
'off',
|
|
||||||
$BLOGLANG["Read More"]
|
|
||||||
);
|
);
|
||||||
include './res/php/Disqus.php'; // include disques
|
include './res/php/Disqus.php'; // include disques
|
||||||
} else { // SOMETHING STRANGE: THIS SHOULDN'T HAPPEN
|
} else { // SOMETHING STRANGE: THIS SHOULDN'T HAPPEN
|
||||||
|
@ -439,14 +417,14 @@ if ($config["design"]["drawer"] == "on") {
|
||||||
<script src="./res/js/app.js"></script> <!--include main javascript-->
|
<script src="./res/js/app.js"></script> <!--include main javascript-->
|
||||||
<!-- JS extension support -->
|
<!-- JS extension support -->
|
||||||
<?php
|
<?php
|
||||||
if (file_exists("./extensions")) {
|
if(file_exists("./extensions")) {
|
||||||
$extensions = scandir('./extensions');
|
$extensions = scandir('./extensions');
|
||||||
foreach ($extensions as $extension) {
|
foreach ($extensions as $extension) {
|
||||||
if (substr($extension, -3) == ".js") {
|
if (substr($extension, -3) == ".js") {
|
||||||
echo "<script src='./extensions/$extension'></script>";
|
echo "<script src='./extensions/$extension'></script>";
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
?>
|
?>
|
||||||
<?php
|
<?php
|
||||||
require './res/php/GoogleAnalytics.php'; // include google analytics
|
require './res/php/GoogleAnalytics.php'; // include google analytics
|
||||||
|
|
|
@ -8,5 +8,4 @@ $BLOGLANG = [
|
||||||
"Check out" => "Schau dir das an:",
|
"Check out" => "Schau dir das an:",
|
||||||
"Next Page" => "Nächste Seite",
|
"Next Page" => "Nächste Seite",
|
||||||
"Previous Page" => "Vorherige Seite",
|
"Previous Page" => "Vorherige Seite",
|
||||||
"Read More" => "Weiterlesen",
|
|
||||||
];
|
];
|
||||||
|
|
|
@ -8,5 +8,4 @@ $BLOGLANG = [
|
||||||
"Check out" => "Check out:",
|
"Check out" => "Check out:",
|
||||||
"Next Page" => "Next Page",
|
"Next Page" => "Next Page",
|
||||||
"Previous Page" => "Previous Page",
|
"Previous Page" => "Previous Page",
|
||||||
"Read More" => "Read More",
|
|
||||||
];
|
];
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"name": "rangitaki",
|
"name": "rangitaki",
|
||||||
"version": "1.5.0",
|
"version": "1.4.0",
|
||||||
"description": "A simple PHP blogging engine without any database dependencies",
|
"description": "A simple PHP blogging engine without any database dependencies",
|
||||||
"main": "index.php",
|
"main": "index.php",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
|
@ -21,7 +21,6 @@
|
||||||
},
|
},
|
||||||
"homepage": "https://gitlab.com/mmk2410/rangitaki#README",
|
"homepage": "https://gitlab.com/mmk2410/rangitaki#README",
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"coffee-script": "^1.10.0",
|
|
||||||
"del": "^2.2.0",
|
"del": "^2.2.0",
|
||||||
"gulp": "^3.9.1",
|
"gulp": "^3.9.1",
|
||||||
"gulp-coffee": "^2.3.2",
|
"gulp-coffee": "^2.3.2",
|
||||||
|
@ -31,7 +30,6 @@
|
||||||
"gulp-size": "^2.1.0",
|
"gulp-size": "^2.1.0",
|
||||||
"gulp-sourcemaps": "^2.0.0-alpha",
|
"gulp-sourcemaps": "^2.0.0-alpha",
|
||||||
"gulp-uglify": "^1.5.3",
|
"gulp-uglify": "^1.5.3",
|
||||||
"merge-stream": "^1.0.0",
|
"merge-stream": "^1.0.0"
|
||||||
"node-sass": "^3.7.0"
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
52
rcc/api/auth/DigestAuth.php
Normal file
52
rcc/api/auth/DigestAuth.php
Normal file
|
@ -0,0 +1,52 @@
|
||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* PHP Version 7
|
||||||
|
*
|
||||||
|
* Authentication Helper Class
|
||||||
|
*
|
||||||
|
* @category Authentication
|
||||||
|
* @package Rbe
|
||||||
|
* @author Marcel Kapfer (mmk2410) <marcelmichaelkapfer@yahoo.co.nz>
|
||||||
|
* @license MIT License
|
||||||
|
* @link http://marcel-kapfer.de/rangitaki
|
||||||
|
*/
|
||||||
|
namespace mmk2410\rbe\digestAuth;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* PHP Version 7
|
||||||
|
*
|
||||||
|
* Authentication Helper Class
|
||||||
|
*
|
||||||
|
* @category Authentication
|
||||||
|
* @package Rbe
|
||||||
|
* @author Marcel Kapfer (mmk2410) <marcelmichaelkapfer@yahoo.co.nz>
|
||||||
|
* @license MIT License
|
||||||
|
* @link http://marcel-kapfer.de/rangitaki
|
||||||
|
*/
|
||||||
|
class DigestAuth
|
||||||
|
{
|
||||||
|
|
||||||
|
/**
|
||||||
|
* parser for http digest
|
||||||
|
*
|
||||||
|
* @param $txt data to parse
|
||||||
|
*
|
||||||
|
* @return parsed data or FALSE
|
||||||
|
*/
|
||||||
|
public function httpDigestParse($txt)
|
||||||
|
{
|
||||||
|
// protect against missing data
|
||||||
|
$needed_parts = array('nonce'=>1, 'nc'=>1, 'cnonce'=>1, 'qop'=>1, 'username'=>1, 'uri'=>1, 'response'=>1);
|
||||||
|
$data = array();
|
||||||
|
$keys = implode('|', array_keys($needed_parts));
|
||||||
|
|
||||||
|
preg_match_all('@(' . $keys . ')=(?:([\'"])([^\2]+?)\2|([^\s,]+))@', $txt, $matches, PREG_SET_ORDER);
|
||||||
|
|
||||||
|
foreach ($matches as $m) {
|
||||||
|
$data[$m[1]] = $m[3] ? $m[3] : $m[4];
|
||||||
|
unset($needed_parts[$m[1]]);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $needed_parts ? false : $data;
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,22 +1,39 @@
|
||||||
<?php
|
<?php
|
||||||
// Marcel Kapfer (mmk2410)
|
// Marcel Kapfer (mmk2410)
|
||||||
// License: MIT License
|
// License: MIT License
|
||||||
// HTTP Basic Auth for the API
|
// api digest auth
|
||||||
|
|
||||||
$basedir = "../../../";
|
require 'DigestAuth.php';
|
||||||
|
|
||||||
require '../../ssl.php';
|
|
||||||
|
|
||||||
require '../../password.php';
|
require '../../password.php';
|
||||||
|
|
||||||
if (!isset($_SERVER['PHP_AUTH_USER'])) {
|
use \mmk2410\rbe\digestAuth\DigestAuth as DigestAuth;
|
||||||
header('WWW-Authenticate: Basic realm="RCC API"');
|
|
||||||
|
$realm = 'Restricted area';
|
||||||
|
|
||||||
|
$users = array($username => $password);
|
||||||
|
|
||||||
|
if (empty($_SERVER['PHP_AUTH_DIGEST'])) {
|
||||||
header('HTTP/1.1 401 Unauthorized');
|
header('HTTP/1.1 401 Unauthorized');
|
||||||
echo "Access denied to the RCC API!";
|
header('WWW-Authenticate: Digest realm="'.$realm.
|
||||||
exit;
|
'",qop="auth",nonce="'.uniqid().'",opaque="'.md5($realm).'"');
|
||||||
} elseif ($_SERVER['PHP_AUTH_USER'] != $username ||
|
|
||||||
!password_verify($_SERVER['PHP_AUTH_PW'], $password)) {
|
die('Access to RCC API not granted');
|
||||||
header('HTTP/1.1 401 Unauthorized');
|
}
|
||||||
echo "Wrong credentials: Access denied!";
|
|
||||||
exit;
|
|
||||||
|
// analyze the PHP_AUTH_DIGEST variable
|
||||||
|
if (!($data = DigestAuth::httpDigestParse($_SERVER['PHP_AUTH_DIGEST'])) ||
|
||||||
|
!isset($users[$data['username']])) {
|
||||||
|
die('Wrong Credentials!');
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// generate the valid response
|
||||||
|
$A1 = md5($data['username'] . ':' . $realm . ':' . $users[$data['username']]);
|
||||||
|
$A2 = md5($_SERVER['REQUEST_METHOD'].':'.$data['uri']);
|
||||||
|
$valid_response = md5($A1.':'.$data['nonce'].':'.$data['nc'].':'.$data['cnonce'].':'.$data['qop'].':'.$A2);
|
||||||
|
|
||||||
|
if ($data['response'] != $valid_response) {
|
||||||
|
die('Wrong Credentials!');
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,13 +9,13 @@ use \Psr\Http\Message\ResponseInterface as Response;
|
||||||
require '../../../vendor/autoload.php';
|
require '../../../vendor/autoload.php';
|
||||||
require '../../../res/php/Config.php';
|
require '../../../res/php/Config.php';
|
||||||
|
|
||||||
|
include '../auth/auth.php';
|
||||||
|
|
||||||
use \mmk2410\rbe\config\Config as Config;
|
use \mmk2410\rbe\config\Config as Config;
|
||||||
|
|
||||||
$config = new Config("../../../config.yaml", '../../../vendor/autoload.php');
|
$config = new Config("../../../config.yaml", '../../../vendor/autoload.php');
|
||||||
$settings = $config->getConfig();
|
$settings = $config->getConfig();
|
||||||
|
|
||||||
include '../auth/auth.php';
|
|
||||||
|
|
||||||
if ($settings["rcc"]["api"] == "on" && $settings["rcc"]["rcc"] == "on") {
|
if ($settings["rcc"]["api"] == "on" && $settings["rcc"]["rcc"] == "on") {
|
||||||
$app = new \Slim\App();
|
$app = new \Slim\App();
|
||||||
|
|
||||||
|
|
|
@ -10,13 +10,13 @@ require '../../../vendor/autoload.php';
|
||||||
require '../../../res/php/Config.php';
|
require '../../../res/php/Config.php';
|
||||||
require '../../../res/php/ArticleGenerator.php';
|
require '../../../res/php/ArticleGenerator.php';
|
||||||
|
|
||||||
|
include '../auth/auth.php';
|
||||||
|
|
||||||
use \mmk2410\rbe\config\Config as Config;
|
use \mmk2410\rbe\config\Config as Config;
|
||||||
|
|
||||||
$config = new Config("../../../config.yaml", '../../../vendor/autoload.php');
|
$config = new Config("../../../config.yaml", '../../../vendor/autoload.php');
|
||||||
$settings = $config->getConfig();
|
$settings = $config->getConfig();
|
||||||
|
|
||||||
include '../auth/auth.php';
|
|
||||||
|
|
||||||
if ($settings["rcc"]["api"] == "on" && $settings["rcc"]["rcc"] == "on") {
|
if ($settings["rcc"]["api"] == "on" && $settings["rcc"]["rcc"] == "on") {
|
||||||
$app = new \Slim\App();
|
$app = new \Slim\App();
|
||||||
|
|
||||||
|
|
|
@ -10,13 +10,13 @@ require '../../../vendor/autoload.php';
|
||||||
require '../../../res/php/Config.php';
|
require '../../../res/php/Config.php';
|
||||||
require '../../../res/php/ArticleGenerator.php';
|
require '../../../res/php/ArticleGenerator.php';
|
||||||
|
|
||||||
|
include '../auth/auth.php';
|
||||||
|
|
||||||
use \mmk2410\rbe\config\Config as Config;
|
use \mmk2410\rbe\config\Config as Config;
|
||||||
|
|
||||||
$config = new Config("../../../config.yaml", '../../../vendor/autoload.php');
|
$config = new Config("../../../config.yaml", '../../../vendor/autoload.php');
|
||||||
$settings = $config->getConfig();
|
$settings = $config->getConfig();
|
||||||
|
|
||||||
include '../auth/auth.php';
|
|
||||||
|
|
||||||
if ($settings["rcc"]["api"] == "on" && $settings["rcc"]["rcc"] == "on") {
|
if ($settings["rcc"]["api"] == "on" && $settings["rcc"]["rcc"] == "on") {
|
||||||
$app = new \Slim\App();
|
$app = new \Slim\App();
|
||||||
|
|
||||||
|
|
|
@ -6,13 +6,13 @@
|
||||||
* @package Rcc
|
* @package Rcc
|
||||||
* @author Marcel Kapfer (mmk2410) <marcelmichaelkapfer@yahoo.co.nz>
|
* @author Marcel Kapfer (mmk2410) <marcelmichaelkapfer@yahoo.co.nz>
|
||||||
* @license MIT License
|
* @license MIT License
|
||||||
* @link https://gitlab.com/mmk2410/rangitaki
|
* @link https://github.com/mmk2410/rangitaki
|
||||||
*
|
*
|
||||||
* Feed Generator
|
* Feed Generator
|
||||||
*
|
*
|
||||||
* The MIT License
|
* The MIT License
|
||||||
*
|
*
|
||||||
* Copyright 2015 - 2016 (c) mmk2410.
|
* Copyright 2015 mmk2410.
|
||||||
*
|
*
|
||||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
* of this software and associated documentation files (the "Software"), to deal
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
@ -36,35 +36,27 @@
|
||||||
date_default_timezone_set('UTC');
|
date_default_timezone_set('UTC');
|
||||||
|
|
||||||
require "../../vendor/autoload.php";
|
require "../../vendor/autoload.php";
|
||||||
require "../../res/php/Config.php";
|
require_once "../../config.php";
|
||||||
require_once "../../res/php/ArticleGenerator.php";
|
require_once "../../res/php/ArticleGenerator.php";
|
||||||
use PicoFeed\Syndication\AtomFeedBuilder;
|
use PicoFeed\Syndication\Atom;
|
||||||
use PicoFeed\Syndication\AtomItemBuilder;
|
|
||||||
use \mmk2410\rbe\config\Config as Config;
|
|
||||||
|
|
||||||
$config = new Config('../../config.yaml', '../../vendor/autoload.php');
|
|
||||||
$settings = $config->getConfig();
|
|
||||||
|
|
||||||
include '../ssl.php';
|
|
||||||
|
|
||||||
session_start();
|
session_start();
|
||||||
|
|
||||||
if ($_SESSION['login']) {
|
if ($_SESSION['login']) {
|
||||||
|
|
||||||
$art_dir = "./../../articles/" . $_GET['blog'] . "/";
|
$art_dir = "./../../articles/" . $_GET['blog'] . "/";
|
||||||
$feed_path = "./../../feed/" . $_GET['blog'] . ".atom";
|
$feed_path = "./../../feed/" . $_GET['blog'] . ".atom";
|
||||||
|
|
||||||
if ($_GET['blog'] == "main") {
|
$writer = new Atom();
|
||||||
$blogtitle = $settings['blog']['title'];
|
|
||||||
} else {
|
|
||||||
$blogtitl = $settings['blog']['title'] . " - " . ucwords($_GET['blog']);
|
|
||||||
}
|
|
||||||
|
|
||||||
$feedBuilder = AtomFeedBuilder::create()
|
$writer->title = $blogtitle;
|
||||||
->withTitle($blogtitle)
|
$writer->site_url = $blogurl;
|
||||||
->withAuthor($settings['blog']['author'])
|
$writer->feed_url = $blogurl . "/feed/" . $_GET['blog'] . ".atom";
|
||||||
->withFeedUrl($settings['blog']['url'] . "/feed/" . $_GET['blog'] . ".atom")
|
$writer->author = array(
|
||||||
->withSiteUrl($settings['blog']['url'])
|
'name' => $blogauthor,
|
||||||
->withDate(new DateTime(date(DATE_ATOM)));
|
'url' => $blogurl,
|
||||||
|
'email' => ''
|
||||||
|
);
|
||||||
|
|
||||||
$articles = scandir($art_dir, 1);
|
$articles = scandir($art_dir, 1);
|
||||||
|
|
||||||
|
@ -79,45 +71,25 @@ if ($_SESSION['login']) {
|
||||||
$text = Parsedown::instance()
|
$text = Parsedown::instance()
|
||||||
->setBreaksEnabled(true)// with linebreaks
|
->setBreaksEnabled(true)// with linebreaks
|
||||||
->text($file);
|
->text($file);
|
||||||
if (new DateTime(date(DATE_ATOM, strtotime($datestring))) != null) {
|
$writer->items[] = array(
|
||||||
$date = new DateTime(
|
'title' => ArticleGenerator::getTitle($art_dir, $article),
|
||||||
date(
|
'updated' => strtotime(
|
||||||
DATE_ATOM,
|
ArticleGenerator::getDate($art_dir . $article)
|
||||||
strtotime($datestring)
|
),
|
||||||
)
|
'url' => $blogurl . "./?article=" .
|
||||||
);
|
substr($article, 0, strlen($article) - 3),
|
||||||
} else {
|
'summary'=> ArticleGenerator::getSummary(
|
||||||
$date = new DateTime(date(DATE_ATOM));
|
$art_dir, $article
|
||||||
}
|
),
|
||||||
$date = new DateTime(date(DATE_ATOM));
|
'content' => $text
|
||||||
$feedBuilder
|
);
|
||||||
->withItem(AtomItemBuilder::create($feedBuilder)
|
|
||||||
->withTitle(
|
|
||||||
ArticleGenerator::getTitle($art_dir, $article)
|
|
||||||
)
|
|
||||||
->withUrl(
|
|
||||||
$settings['blog']['url'] . "./?article=" . substr($article, 0, strlen($article) - 3)
|
|
||||||
)
|
|
||||||
->withAuthor(
|
|
||||||
ArticleGenerator::getAuthor($art_dir, $article)
|
|
||||||
)
|
|
||||||
->withPublishedDate(
|
|
||||||
parseDate(ArticleGenerator::getDate($art_dir, $article))
|
|
||||||
)
|
|
||||||
->withUpdatedDate(
|
|
||||||
parseDate(ArticleGenerator::getDate($art_dir, $article))
|
|
||||||
)
|
|
||||||
->withSummary(
|
|
||||||
ArticleGenerator::getSummary($art_dir, $article)
|
|
||||||
)
|
|
||||||
->withContent($text));
|
|
||||||
$amount += 1;
|
$amount += 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
$feed = $feedBuilder->build();
|
$feed = $writer->execute();
|
||||||
|
|
||||||
$file = fopen($feed_path, "w");
|
$file = fopen($feed_path, "w");
|
||||||
|
|
||||||
|
@ -130,19 +102,4 @@ if ($_SESSION['login']) {
|
||||||
|
|
||||||
echo "0";
|
echo "0";
|
||||||
}
|
}
|
||||||
|
?>
|
||||||
function parseDate($datestring)
|
|
||||||
{
|
|
||||||
$datetime = new DateTime(date(DATE_ATOM));
|
|
||||||
try {
|
|
||||||
$datetime = new DateTime(
|
|
||||||
date(
|
|
||||||
DATE_ATOM,
|
|
||||||
strtotime($datestring)
|
|
||||||
)
|
|
||||||
);
|
|
||||||
} catch (Exception $e) {
|
|
||||||
$datetime = new DateTime(date(DATE_ATOM));
|
|
||||||
}
|
|
||||||
return $datetime;
|
|
||||||
}
|
|
||||||
|
|
|
@ -32,19 +32,6 @@
|
||||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
* THE SOFTWARE.
|
* THE SOFTWARE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
require '../vendor/autoload.php';
|
|
||||||
require '../res/php/Config.php';
|
|
||||||
require "./../res/php/BlogListGenerator.php";
|
|
||||||
|
|
||||||
use \mmk2410\rbe\config\Config as Config;
|
|
||||||
use mmk2410\rbe\BlogListGenerator\BlogListGenerator as BlogListGenerator;
|
|
||||||
|
|
||||||
$config = new Config("../config.yaml", '../vendor/autoload.php');
|
|
||||||
$settings = $config->getConfig();
|
|
||||||
|
|
||||||
include './ssl.php';
|
|
||||||
|
|
||||||
?>
|
?>
|
||||||
|
|
||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
|
@ -77,7 +64,12 @@ include './ssl.php';
|
||||||
|
|
||||||
<div class="main">
|
<div class="main">
|
||||||
<?php
|
<?php
|
||||||
$config = $settings;
|
require '../res/php/Config.php';
|
||||||
|
use mmk2410\rbe\config\Config as Config;
|
||||||
|
|
||||||
|
$configParser = new Config('../config.yaml', '../vendor/autoload.php');
|
||||||
|
|
||||||
|
$config = $configParser->getConfig();
|
||||||
|
|
||||||
if ($config["rcc"]["rcc"] == "on") {
|
if ($config["rcc"]["rcc"] == "on") {
|
||||||
include 'password.php';
|
include 'password.php';
|
||||||
|
@ -108,9 +100,9 @@ if ($config["rcc"]["rcc"] == "on") {
|
||||||
|
|
||||||
<?php
|
<?php
|
||||||
} else {
|
} else {
|
||||||
if (password_verify($passwd, $password)) {
|
if ($passwd == $password) {
|
||||||
$_SESSION['login'] = true;
|
$_SESSION['login'] = true;
|
||||||
|
include_once "./../res/php/BlogListGenerator.php";
|
||||||
?>
|
?>
|
||||||
|
|
||||||
<!-- Post Upload -->
|
<!-- Post Upload -->
|
||||||
|
@ -124,10 +116,8 @@ if ($config["rcc"]["rcc"] == "on") {
|
||||||
$blogs = scandir("../blogs/");
|
$blogs = scandir("../blogs/");
|
||||||
foreach ($blogs as $blog) {
|
foreach ($blogs as $blog) {
|
||||||
if (strlen($blog) >= 3 && substr($blog, -3) == ".md") {
|
if (strlen($blog) >= 3 && substr($blog, -3) == ".md") {
|
||||||
if (BlogListGenerator::getExternalLink($blog, '../') == null) {
|
$blog = substr($blog, 0, -3);
|
||||||
$blog = substr($blog, 0, -3);
|
echo "<option value='$blog'>$blog</option>";
|
||||||
echo "<option value='$blog'>$blog</option>";
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
?>
|
?>
|
||||||
|
@ -151,10 +141,8 @@ if ($config["rcc"]["rcc"] == "on") {
|
||||||
$blogs = scandir("../blogs/");
|
$blogs = scandir("../blogs/");
|
||||||
foreach ($blogs as $blog) {
|
foreach ($blogs as $blog) {
|
||||||
if (strlen($blog) >= 3 && substr($blog, -3) == ".md") {
|
if (strlen($blog) >= 3 && substr($blog, -3) == ".md") {
|
||||||
if (BlogListGenerator::getExternalLink($blog, '../') == null) {
|
$blog = substr($blog, 0, -3);
|
||||||
$blog = substr($blog, 0, -3);
|
echo "<option value='$blog'>$blog</option>";
|
||||||
echo "<option value='$blog'>$blog</option>";
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
?>
|
?>
|
||||||
|
@ -201,10 +189,8 @@ if ($config["rcc"]["rcc"] == "on") {
|
||||||
$blogs = scandir("../blogs/");
|
$blogs = scandir("../blogs/");
|
||||||
foreach ($blogs as $blog) {
|
foreach ($blogs as $blog) {
|
||||||
if (strlen($blog) >= 3 && substr($blog, -3) == ".md") {
|
if (strlen($blog) >= 3 && substr($blog, -3) == ".md") {
|
||||||
if (BlogListGenerator::getExternalLink($blog, '../') == null) {
|
$blog = substr($blog, 0, -3);
|
||||||
$blog = substr($blog, 0, -3);
|
echo "<option value='$blog'>$blog</option>";
|
||||||
echo "<option value='$blog'>$blog</option>";
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
?>
|
?>
|
||||||
|
@ -226,10 +212,8 @@ if ($config["rcc"]["rcc"] == "on") {
|
||||||
$blogs = scandir("../blogs/");
|
$blogs = scandir("../blogs/");
|
||||||
foreach ($blogs as $blog) {
|
foreach ($blogs as $blog) {
|
||||||
if (strlen($blog) >= 3 && substr($blog, -3) == ".md") {
|
if (strlen($blog) >= 3 && substr($blog, -3) == ".md") {
|
||||||
if (BlogListGenerator::getExternalLink($blog, '../') == null) {
|
$blog = substr($blog, 0, -3);
|
||||||
$blog = substr($blog, 0, -3);
|
echo "<option value='$blog'>$blog</option>";
|
||||||
echo "<option value='$blog'>$blog</option>";
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
?>
|
?>
|
||||||
|
@ -259,10 +243,8 @@ if ($config["rcc"]["rcc"] == "on") {
|
||||||
$blogs = scandir("../blogs/");
|
$blogs = scandir("../blogs/");
|
||||||
foreach ($blogs as $blog) {
|
foreach ($blogs as $blog) {
|
||||||
if (strlen($blog) >= 3 && substr($blog, -3) == ".md") {
|
if (strlen($blog) >= 3 && substr($blog, -3) == ".md") {
|
||||||
if (BlogListGenerator::getExternalLink($blog, '../') == null) {
|
$blog = substr($blog, 0, -3);
|
||||||
$blog = substr($blog, 0, -3);
|
echo "<option value='$blog'>$blog</option>";
|
||||||
echo "<option value='$blog'>$blog</option>";
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
?>
|
?>
|
||||||
|
|
|
@ -1,3 +1,3 @@
|
||||||
<?php
|
<?php
|
||||||
$username = "test";
|
$username = "example";
|
||||||
$password = '$2y$12$nHitKTwHqU4GmI3ADVE05eH/723fCNgdQ65kQ53FyZUVVB03BjfCO';
|
$password = "example";
|
||||||
|
|
11
rcc/ssl.php
11
rcc/ssl.php
|
@ -1,11 +0,0 @@
|
||||||
<?php
|
|
||||||
// Marcel Kapfer (mmk2410) / Wilson O'Sullivan
|
|
||||||
// License: MIT License
|
|
||||||
// SSL Verification
|
|
||||||
|
|
||||||
if (isset($settings["rcc"]["debug"]) && $settings["rcc"]["debug"] != "on") {
|
|
||||||
if (empty($_SERVER['HTTPS']) || $_SERVER['HTTPS'] != "on") {
|
|
||||||
header('HTTP/1.1 400 Bad Request');
|
|
||||||
exit();
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,3 +1,3 @@
|
||||||
body{margin-top:94px}.main{height:100%;margin-left:0}.overlay{opacity:0;position:fixed;top:0;left:0;background-color:black;width:100%;z-index:30;height:100%;display:none}.header{top:0;right:0;left:0;width:100%;height:64px;position:absolute}.title{color:#fff;font-size:23px;text-decoration:none;line-height:64px;vertical-align:middle;left:75px}.title>a{text-decoration:none;color:#fff}.fadeout{position:absolute;height:64px;top:0;right:0;width:40px}.nav-img{height:26px;padding:19px;cursor:pointer}.nav{width:300px;position:fixed;height:100%;top:0;left:-301px;z-index:40}.nav-item,.nav-item-static{text-decoration:none;text-indent:0;display:inline-block;height:48px;vertical-align:middle;width:284px;line-height:48px;padding-left:16px;transition:background-color 125ms ease-in-out 0ms}.nav-close{cursor:pointer}.nav-close-img{height:35px;padding:12px}.nav-item{cursor:pointer}.divider{width:100%}.card{margin-right:auto;margin-left:auto;width:75%;padding:24px;margin-bottom:40px;max-width:1160px}.card a{-moz-hyphens:auto;-epub-hyphens:auto;-ms-hyphens:auto;-webkit-hyphens:auto;hyphens:auto;word-wrap:break-word}.headline{display:block;padding-bottom:8px}.card img{max-width:100%;max-height:400px;display:block;margin-left:auto;margin-right:auto}.author{display:block}.readmore{padding:12px 0 25px 0}.fabmenu{position:fixed;bottom:20px;right:20px}.fab{height:60px;width:60px;border-radius:30px;cursor:pointer}.fab-img{width:28px;padding:15px}.subfab{height:45px;width:45px;border-radius:30px;margin-right:auto;margin-left:auto;margin-bottom:25px;display:none}.subfab-img{width:22px;padding:12px}.pag_buttons{margin-right:auto;margin-left:auto;width:calc(75% + 48px);margin-bottom:80px;max-width:1160px;text-align:right}.button{text-decoration:none;color:#fff;line-height:36px;min-width:64px;text-align:center;height:36px;padding:8px;margin-top:4px;margin-bottom:5px;cursor:pointer}.pag_next{margin-left:8px}.footer a{transition:border-bottom-color 150ms ease-in-out 100ms}.footer a:hover{border-bottom-color:#383838}@media screen and (min-width: 1440px){.nav{left:0;padding-top:64px}.nav-close-img{display:none}.nav-close{display:none}.nav-img{display:none}.header{left:300px}.main{margin-left:300px;width:calc(100% - 300px)}}@media screen and (max-width: 720px){.card{width:82%}.pag_buttons{width:calc(82% + 48px)}}
|
body{margin-top:94px}.main{height:100%;margin-left:0}.overlay{opacity:0;position:fixed;top:0;left:0;background-color:black;width:100%;z-index:30;height:100%;display:none}.header{top:0;right:0;left:0;width:100%;height:64px;position:absolute}.title{color:#fff;font-size:23px;text-decoration:none;line-height:64px;vertical-align:middle;left:75px}.title>a{text-decoration:none;color:#fff}.fadeout{position:absolute;height:64px;top:0;right:0;width:40px}.nav-img{height:26px;padding:19px;cursor:pointer}.nav{width:300px;position:fixed;height:100%;top:0;left:-301px;z-index:40}.nav-item,.nav-item-static{text-decoration:none;text-indent:0;display:inline-block;height:48px;vertical-align:middle;width:284px;line-height:48px;padding-left:16px;transition:background-color 125ms ease-in-out 0ms}.nav-close{cursor:pointer}.nav-close-img{height:35px;padding:12px}.nav-item{cursor:pointer}.divider{width:100%}.card{margin-right:auto;margin-left:auto;width:75%;padding:24px;margin-bottom:40px;max-width:1160px}.card a{-moz-hyphens:auto;-epub-hyphens:auto;-ms-hyphens:auto;-webkit-hyphens:auto;hyphens:auto;word-wrap:break-word}.headline{display:block;padding-bottom:8px}.card img{max-width:100%;max-height:400px;display:block;margin-left:auto;margin-right:auto}.author{display:block}.fabmenu{position:fixed;bottom:20px;right:20px}.fab{height:60px;width:60px;border-radius:30px;cursor:pointer}.fab-img{width:28px;padding:15px}.subfab{height:45px;width:45px;border-radius:30px;margin-right:auto;margin-left:auto;margin-bottom:25px;display:none}.subfab-img{width:22px;padding:12px}.pag_buttons{margin-right:auto;margin-left:auto;width:calc(75% + 48px);margin-bottom:80px;max-width:1160px;text-align:right}.button{text-decoration:none;color:#fff;line-height:36px;min-width:64px;text-align:center;height:36px;padding:8px;margin-top:4px;margin-bottom:5px;cursor:pointer}.pag_next{margin-left:8px}.footer a{transition:border-bottom-color 150ms ease-in-out 100ms}.footer a:hover{border-bottom-color:#383838}@media screen and (min-width: 1440px){.nav{left:0;padding-top:64px}.nav-close-img{display:none}.nav-close{display:none}.nav-img{display:none}.header{left:300px}.main{margin-left:300px;width:calc(100% - 300px)}}@media screen and (max-width: 720px){.card{width:82%}.pag_buttons{width:calc(82% + 48px)}}
|
||||||
|
|
||||||
/*# sourceMappingURL=rangitaki.css.map */
|
/*# sourceMappingURL=rangitaki.css.map */
|
||||||
|
|
File diff suppressed because one or more lines are too long
|
@ -1 +1 @@
|
||||||
(function(){var n,t,a,e,r;e=function(){var e,i;return e=!1,$(".fabmenu").click(function(){return e?(a(),e=!1):(t(),e=!0)}),i=!1,$(".nav-img, .overlay, .nav-close").click(function(){return i?(n(),i=!1):(r(),i=!0)}),$(document).keyup(function(t){return i&&27===t.which?(n(),i=!1):i||77!==t.which?void 0:(r(),i=!0)}),$(".articletext a").attr("target","_blank")},$(document).ready(e),t=function(){return $(".subfab").fadeIn(125),$(".fab-img").fadeOut(60,function(){return $(".fab-img").attr("src","./res/img/close.svg"),$(".fab-img").fadeIn(60)})},a=function(){return $(".subfab").fadeOut(125),$(".fab-img").fadeOut(60,function(){return $(".fab-img").attr("src","./res/img/share.svg"),$(".fab-img").fadeIn(60)})},r=function(){return $(".nav").animate({left:"0px"},125),$(".overlay").show(),$(".overlay").animate({opacity:"0.4"},125)},n=function(){return $(".nav").animate({left:"-301px"},125),$(".overlay").animate({opacity:"0.0"},125,function(){return $(".overlay").css({display:"none"})})}}).call(this);
|
(function(){var n,t,a,e,r,i;r=function(){var e,r;return e=!1,$(".fabmenu").click(function(){return e?(a(),e=!1):(t(),e=!0)}),r=!1,$(".nav-img, .overlay, .nav-close").click(function(){return r?(n(),r=!1):(i(),r=!0)}),$(document).keyup(function(t){return r&&27===t.which?(n(),r=!1):r||77!==t.which?void 0:(i(),r=!0)}),$(".articletext a").attr("target","_blank")},$(document).ready(r),e=function(){return history.go(-1)},t=function(){return $(".subfab").fadeIn(125),$(".fab-img").fadeOut(60,function(){return $(".fab-img").attr("src","./res/img/close.svg"),$(".fab-img").fadeIn(60)})},a=function(){return $(".subfab").fadeOut(125),$(".fab-img").fadeOut(60,function(){return $(".fab-img").attr("src","./res/img/share.svg"),$(".fab-img").fadeIn(60)})},i=function(){return $(".nav").animate({left:"0px"},125),$(".overlay").show(),$(".overlay").animate({opacity:"0.4"},125)},n=function(){return $(".nav").animate({left:"-301px"},125),$(".overlay").animate({opacity:"0.0"},125,function(){return $(".overlay").hide})}}).call(this);
|
|
@ -59,7 +59,7 @@ class ArticleGenerator
|
||||||
*
|
*
|
||||||
* @return Null
|
* @return Null
|
||||||
*/
|
*/
|
||||||
function newArticle($directory, $articlefile, $blog, $excerpt, $readmore)
|
function newArticle($directory, $articlefile, $blog)
|
||||||
{
|
{
|
||||||
|
|
||||||
$article = file_get_contents($directory . $articlefile); // get the file
|
$article = file_get_contents($directory . $articlefile); // get the file
|
||||||
|
@ -96,39 +96,12 @@ class ArticleGenerator
|
||||||
|
|
||||||
echo "<div class='articletext'>";
|
echo "<div class='articletext'>";
|
||||||
|
|
||||||
// print only a excerpt of the post
|
|
||||||
// with at least 200 characters if possible.
|
|
||||||
if ( $excerpt == 'on' ) {
|
|
||||||
$emptyline = strpos($article, "\n\n");
|
|
||||||
if ( $emptyline !== false ) {
|
|
||||||
if ( $emptyline < 200) {
|
|
||||||
$emptyline2 = strpos($article, "\n\n", $emptyline);
|
|
||||||
if ( $emptyline2 !== false ) {
|
|
||||||
$article = substr($article, 0, $emptyline2);
|
|
||||||
} else {
|
|
||||||
$article = substr($article, 0, $emptyline);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
$article = substr($article, 0, $emptyline);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// correct $excerpt for use in line 127.
|
|
||||||
$excerpt = 'off';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
echo Parsedown::instance()
|
echo Parsedown::instance()
|
||||||
->setBreaksEnabled(true)
|
->setBreaksEnabled(true)
|
||||||
->text($article); // print now the article text as html
|
->text($article); // print now the article text as html
|
||||||
|
|
||||||
echo "</div>";
|
echo "</div>";
|
||||||
|
|
||||||
|
|
||||||
if ( $excerpt == 'on' ) {
|
|
||||||
echo "<div class='readmore'><a href='$link'>$readmore</a></div>";
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
if (isset($author)) {
|
if (isset($author)) {
|
||||||
echo "<span class='author'>$author</span>"; // print the author
|
echo "<span class='author'>$author</span>"; // print the author
|
||||||
}
|
}
|
||||||
|
@ -223,15 +196,15 @@ class ArticleGenerator
|
||||||
*/
|
*/
|
||||||
static function getSummary($directory, $articlefile)
|
static function getSummary($directory, $articlefile)
|
||||||
{
|
{
|
||||||
$text = ArticleGenerator::getText($directory, $articlefile);
|
$text = getText($directory, $articlefile);
|
||||||
|
|
||||||
$pos = stripos($text, "\n\n");
|
$pos = stripos($text, ".");
|
||||||
|
|
||||||
if ($pos !== false) {
|
if ($pos) {
|
||||||
$offset = $pos;
|
$offset = $pos + 1;
|
||||||
$pos = stripos($text, ".", $offset);
|
$pos = stripos($text, ".", $offset);
|
||||||
$summary = substr($text, 0, $pos) . ".";
|
$summary = substr($text, 0, $pos) . ".";
|
||||||
return trim($summary);
|
return $summary;
|
||||||
} else {
|
} else {
|
||||||
return $text;
|
return $text;
|
||||||
}
|
}
|
||||||
|
@ -302,10 +275,6 @@ class ArticleGenerator
|
||||||
public function getArray($directory, $articlefile)
|
public function getArray($directory, $articlefile)
|
||||||
{
|
{
|
||||||
$article = file_get_contents($directory . $articlefile);
|
$article = file_get_contents($directory . $articlefile);
|
||||||
$title = "";
|
|
||||||
$date = "";
|
|
||||||
$author = "";
|
|
||||||
$tags = array();
|
|
||||||
|
|
||||||
if (substr($article, 0, 6) == "%TITLE") { // get and remove the title
|
if (substr($article, 0, 6) == "%TITLE") { // get and remove the title
|
||||||
$title = substr($article, 8, strpos($article, "\n") - 8);
|
$title = substr($article, 8, strpos($article, "\n") - 8);
|
||||||
|
|
|
@ -10,7 +10,7 @@
|
||||||
* @license MIT License
|
* @license MIT License
|
||||||
* @link http://marcel-kapfer.de/rangitaki
|
* @link http://marcel-kapfer.de/rangitaki
|
||||||
*/
|
*/
|
||||||
namespace mmk2410\rbe\BlogListGenerator;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The blog list generator class is a collection of functions for generating
|
* The blog list generator class is a collection of functions for generating
|
||||||
|
@ -37,7 +37,7 @@ class BlogListGenerator
|
||||||
*
|
*
|
||||||
* @return None
|
* @return None
|
||||||
*/
|
*/
|
||||||
public function listBlog($directory, $blogname, $blogmaintitle)
|
function listBlog($directory, $blogname, $blogmaintitle)
|
||||||
{
|
{
|
||||||
// get content of the blog file;
|
// get content of the blog file;
|
||||||
$blog = file_get_contents($directory . $blogname);
|
$blog = file_get_contents($directory . $blogname);
|
||||||
|
@ -46,25 +46,18 @@ class BlogListGenerator
|
||||||
// check if the first line includes a title
|
// check if the first line includes a title
|
||||||
if (substr($blog, 0, 6) == "%TITLE") {
|
if (substr($blog, 0, 6) == "%TITLE") {
|
||||||
// grab the title
|
// grab the title
|
||||||
$itemname = substr($blog, 8, strpos($blog, "\n") - 8);
|
$blog = substr($blog, 8, strpos($blog, "\n") - 8);
|
||||||
// if on main blog
|
// if on main blog
|
||||||
if ($itemname == "main") {
|
if ($blog == "main") {
|
||||||
// create a nav item to the main blog
|
// create a nav item to the main blog
|
||||||
$atag = "<a class='nav-item' href='./'>$blogmaintitle</a>";
|
echo "<a class='nav-item' href='./'>$blogmaintitle</a>";
|
||||||
} else {
|
} else {
|
||||||
// create a link to the blog
|
// create a link to the blog
|
||||||
$link = "./?blog=" . substr($blogname, 0, -3);
|
$link = "./?blog=" . substr($blogname, 0, -3);
|
||||||
// create a nav item to the blog
|
// create a nav item to the blog
|
||||||
$atag = "<a class='nav-item' href='$link'>$itemname</a>";
|
echo "<a class='nav-item' href='$link'>$blog</a>";
|
||||||
}
|
}
|
||||||
$blog = substr($blog, strpos($blog, "\n") + 1);
|
|
||||||
}
|
}
|
||||||
// nav item as link to external page
|
|
||||||
if (substr($blog, 0, 4) == "%URL") {
|
|
||||||
$itemurl = substr($blog, 6, strpos($blog, "\n") - 6);
|
|
||||||
$atag = "<a class='nav-item' href='$itemurl'>$itemname</a>";
|
|
||||||
}
|
|
||||||
return $atag;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -74,7 +67,7 @@ class BlogListGenerator
|
||||||
*
|
*
|
||||||
* @return string
|
* @return string
|
||||||
*/
|
*/
|
||||||
public function getName($file)
|
function getName($file)
|
||||||
{
|
{
|
||||||
// get the content of the blog file
|
// get the content of the blog file
|
||||||
$blog = file_get_contents($file);
|
$blog = file_get_contents($file);
|
||||||
|
@ -96,7 +89,7 @@ class BlogListGenerator
|
||||||
*
|
*
|
||||||
* @return int Amount of files
|
* @return int Amount of files
|
||||||
*/
|
*/
|
||||||
public static function getArticleAmount($blog)
|
static function getArticleAmount($blog)
|
||||||
{
|
{
|
||||||
$directory = "./articles/" . $blog . "/";
|
$directory = "./articles/" . $blog . "/";
|
||||||
if (!file_exists($directory)) {
|
if (!file_exists($directory)) {
|
||||||
|
@ -104,7 +97,7 @@ class BlogListGenerator
|
||||||
} else {
|
} else {
|
||||||
$i = 0;
|
$i = 0;
|
||||||
$handle = opendir($directory);
|
$handle = opendir($directory);
|
||||||
while (($file = readdir($handle)) !== false) {
|
while (($file = readdir($handle)) !== false ) {
|
||||||
if (!in_array($file, array('.','..'))) {
|
if (!in_array($file, array('.','..'))) {
|
||||||
$i++;
|
$i++;
|
||||||
}
|
}
|
||||||
|
@ -113,25 +106,4 @@ class BlogListGenerator
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* A function returning the external linkn of
|
|
||||||
* a blog.
|
|
||||||
*
|
|
||||||
* @param string $blog the blog name
|
|
||||||
* @param string $dir root directory of installation
|
|
||||||
*
|
|
||||||
* @return string link to external page else null
|
|
||||||
*/
|
|
||||||
public function getExternalLink($blog, $dir)
|
|
||||||
{
|
|
||||||
$path = $dir . "/blogs/" . $blog;
|
|
||||||
$blog = file_get_contents($path) . "\n";
|
|
||||||
if (substr($blog, 0, 6) == "%TITLE") {
|
|
||||||
$blog = substr($blog, strpos($blog, "\n") + 1);
|
|
||||||
}
|
|
||||||
if (substr($blog, 0, 4) == "%URL") {
|
|
||||||
return substr($blog, 6, strpos($blog, "\n") - 6);
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -22,7 +22,7 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
THE SOFTWARE.
|
THE SOFTWARE.
|
||||||
-->
|
-->
|
||||||
|
|
||||||
<?php if ($config['blog']['disqus']) { // check if disqus is enabled ?>
|
<?php if ($blogdisqus) { // check if disqus is enabled ?>
|
||||||
<section class="card">
|
<section class="card">
|
||||||
<div id="disqus_thread"></div>
|
<div id="disqus_thread"></div>
|
||||||
<script type="text/javascript">
|
<script type="text/javascript">
|
||||||
|
|
|
@ -11,7 +11,6 @@
|
||||||
* @link http://marcel-kapfer.de/rangitaki
|
* @link http://marcel-kapfer.de/rangitaki
|
||||||
*/
|
*/
|
||||||
require_once "BlogListGenerator.php";
|
require_once "BlogListGenerator.php";
|
||||||
use mmk2410\rbe\BlogListGenerator\BlogListGenerator as BlogListGenerator;
|
|
||||||
|
|
||||||
require_once './res/php/Config.php';
|
require_once './res/php/Config.php';
|
||||||
|
|
||||||
|
|
|
@ -64,6 +64,9 @@ main = () ->
|
||||||
|
|
||||||
$(document).ready main
|
$(document).ready main
|
||||||
|
|
||||||
|
goBack = () ->
|
||||||
|
history.go -1
|
||||||
|
|
||||||
fabFadeIn = () ->
|
fabFadeIn = () ->
|
||||||
$('.subfab').fadeIn 125
|
$('.subfab').fadeIn 125
|
||||||
$('.fab-img').fadeOut 60, ->
|
$('.fab-img').fadeOut 60, ->
|
||||||
|
@ -84,4 +87,5 @@ openNav = () ->
|
||||||
closeNav = () ->
|
closeNav = () ->
|
||||||
$('.nav').animate {"left": "-301px"}, 125
|
$('.nav').animate {"left": "-301px"}, 125
|
||||||
$('.overlay').animate {"opacity": "0.0"}, 125, ->
|
$('.overlay').animate {"opacity": "0.0"}, 125, ->
|
||||||
$('.overlay').css {"display": "none"}
|
$('.overlay').hide
|
||||||
|
|
||||||
|
|
|
@ -1,194 +0,0 @@
|
||||||
/*
|
|
||||||
*The MIT License
|
|
||||||
*
|
|
||||||
*Copyright 2015 mmk2410.
|
|
||||||
*
|
|
||||||
*Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
||||||
*of this software and associated documentation files (the "Software"), to deal
|
|
||||||
*in the Software without restriction, including without limitation the rights
|
|
||||||
*to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
||||||
*copies of the Software, and to permit persons to whom the Software is
|
|
||||||
*furnished to do so, subject to the following conditions:
|
|
||||||
*
|
|
||||||
*The above copyright notice and this permission notice shall be included in
|
|
||||||
*all copies or substantial portions of the Software.
|
|
||||||
*
|
|
||||||
*THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
||||||
*IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
||||||
*FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
||||||
*AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
||||||
*LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
||||||
*OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
||||||
*THE SOFTWARE.
|
|
||||||
/*
|
|
||||||
* Created on : Jun 18, 2015, 6:39:37 PM
|
|
||||||
* Author : mmk2410
|
|
||||||
|
|
||||||
$font: "Fira Sans", sans-serif
|
|
||||||
|
|
||||||
$background: #f0f0f0
|
|
||||||
$text-color: #383838
|
|
||||||
$primary-color: #4CAF50
|
|
||||||
$header-shadow: rgba(62, 62, 62, 0.45)
|
|
||||||
$white: #FFFFFF
|
|
||||||
$fadeout-color: rgba(30, 87, 153, 0)
|
|
||||||
$border: #e0e0e0
|
|
||||||
$active-color: #e2e2e2
|
|
||||||
$fab-shadow: rgba(62, 62, 62, 0.3)
|
|
||||||
$footer-background: #2D2D2D
|
|
||||||
|
|
||||||
body
|
|
||||||
font-family: $font
|
|
||||||
background: $background
|
|
||||||
color: $text-color
|
|
||||||
margin: 130px 0 0
|
|
||||||
|
|
||||||
::selection, ::-moz-selection
|
|
||||||
color: $background
|
|
||||||
background-color: $primary-color
|
|
||||||
|
|
||||||
.header
|
|
||||||
height: 55px
|
|
||||||
background-color: $primary-color
|
|
||||||
position: fixed
|
|
||||||
box-shadow: 2px 0 2px 2px $header-shadow
|
|
||||||
|
|
||||||
.title
|
|
||||||
line-height: 55px
|
|
||||||
color: $white
|
|
||||||
position: absolute
|
|
||||||
left: 0
|
|
||||||
margin-left: calc(20% + 24px)
|
|
||||||
> a
|
|
||||||
color: $white
|
|
||||||
text-decoration: none
|
|
||||||
|
|
||||||
.fadeout
|
|
||||||
height: 55px
|
|
||||||
background: -moz-linear-gradient(left, $fadeout-color 0%, $primary-color 100%)
|
|
||||||
background: -webkit-linear-gradient(left, $fadeout-color 0%, $primary-color 100%)
|
|
||||||
background: -o-linear-gradient(left, $fadeout-color 0%, $primary-color 100%)
|
|
||||||
background: -ms-linear-gradient(left, $fadeout-color 0%, $primary-color 100%)
|
|
||||||
background: linear-gradient(to right, $fadeout-color 0%, $primary-color 100%)
|
|
||||||
|
|
||||||
.nav-img
|
|
||||||
padding: 14px 19px
|
|
||||||
|
|
||||||
.nav
|
|
||||||
background-color: $white
|
|
||||||
border-right: 1px solid $border
|
|
||||||
|
|
||||||
.nav-item, .nav-item-static
|
|
||||||
color: $text-color
|
|
||||||
|
|
||||||
.nav-item
|
|
||||||
font-weight: 600
|
|
||||||
&:hover
|
|
||||||
color: $primary-color
|
|
||||||
&:active
|
|
||||||
background-color: $active-color
|
|
||||||
|
|
||||||
.divider
|
|
||||||
border-bottom: 1px solid $border
|
|
||||||
|
|
||||||
.card
|
|
||||||
background: none
|
|
||||||
border-radius: 0
|
|
||||||
box-shadow: none
|
|
||||||
margin: 0 20% 100px
|
|
||||||
width: auto
|
|
||||||
a
|
|
||||||
color: $primary-color
|
|
||||||
text-decoration: none
|
|
||||||
border-bottom: 1px solid transparent
|
|
||||||
transition: border-bottom-color 150ms ease-in-out 100ms
|
|
||||||
&:hover
|
|
||||||
border-bottom-color: #4CAF50
|
|
||||||
|
|
||||||
.headline
|
|
||||||
font-size: 30px
|
|
||||||
line-height: 50px
|
|
||||||
color: #383838 !important
|
|
||||||
text-decoration: none
|
|
||||||
border-bottom: none !important
|
|
||||||
&:hover
|
|
||||||
color: #4CAF50 !important
|
|
||||||
|
|
||||||
.date
|
|
||||||
font-size: 13px
|
|
||||||
|
|
||||||
.articletext
|
|
||||||
margin-top: 30px
|
|
||||||
font-size: 16px
|
|
||||||
line-height: 30px
|
|
||||||
|
|
||||||
.author, .tag
|
|
||||||
font-size: 13px
|
|
||||||
|
|
||||||
.fab
|
|
||||||
background-color: $primary-color
|
|
||||||
box-shadow: 0 1px 1.5px 1.5px $fab-shadow
|
|
||||||
|
|
||||||
.subfab
|
|
||||||
background-color: $white
|
|
||||||
box-shadow: 0 1px 1.5px 1.5px $fab-shadow
|
|
||||||
|
|
||||||
.button
|
|
||||||
color: $primary-color
|
|
||||||
border-bottom: 1px solid transparent
|
|
||||||
margin: 0
|
|
||||||
min-width: 0
|
|
||||||
padding: 0
|
|
||||||
line-height: 16px
|
|
||||||
height: 16px
|
|
||||||
transition-property: border-bottom-color
|
|
||||||
transition-delay: 50ms
|
|
||||||
transition-duration: 125ms
|
|
||||||
transition-timing-function: ease
|
|
||||||
-moz-transition-property: border-bottom-color
|
|
||||||
-moz-transition-delay: 50ms
|
|
||||||
-moz-transition-duration: 125ms
|
|
||||||
-moz-transition-timing-function: ease
|
|
||||||
-webkit-transition-property: border-bottom-color
|
|
||||||
-webkit-transition-delay: 50ms
|
|
||||||
-webkit-transition-duration: 125ms
|
|
||||||
-webkit-transition-timing-function: ease
|
|
||||||
&:hover
|
|
||||||
border-bottom-color: $primary-color
|
|
||||||
|
|
||||||
.pag_prev
|
|
||||||
float: left
|
|
||||||
|
|
||||||
.button:last-child
|
|
||||||
float: none
|
|
||||||
|
|
||||||
.footer
|
|
||||||
text-align: center
|
|
||||||
height: 60px
|
|
||||||
background-color: $footer-background
|
|
||||||
line-height: 60px
|
|
||||||
width: 100%
|
|
||||||
color: $white
|
|
||||||
a
|
|
||||||
color: $white
|
|
||||||
text-decoration: none
|
|
||||||
border-bottom: 1px solid transparent
|
|
||||||
&:hover
|
|
||||||
border-bottom-color: $white
|
|
||||||
|
|
||||||
.hljs
|
|
||||||
background: none
|
|
||||||
|
|
||||||
@media screen and (min-width: 1440px)
|
|
||||||
.title
|
|
||||||
margin-left: calc(20% - 40px)
|
|
||||||
.nav
|
|
||||||
padding-top: 55px
|
|
||||||
|
|
||||||
@media screen and (max-width: 800px)
|
|
||||||
body
|
|
||||||
margin-top: 80px
|
|
||||||
.title
|
|
||||||
margin-left: 20%
|
|
||||||
.card
|
|
||||||
margin: 0 5% 100px
|
|
|
@ -153,9 +153,6 @@ body
|
||||||
|
|
||||||
.tag
|
.tag
|
||||||
|
|
||||||
.readmore
|
|
||||||
padding: 12px 0 25px 0
|
|
||||||
|
|
||||||
/* FAB */
|
/* FAB */
|
||||||
|
|
||||||
.fabmenu
|
.fabmenu
|
||||||
|
|
|
@ -1,91 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
require_once 'PHPUnit/Autoload.php';
|
|
||||||
include 'res/php/ArticleGenerator.php';
|
|
||||||
|
|
||||||
class ArticleGeneratorTest extends \PHPUnit_Framework_TestCase
|
|
||||||
{
|
|
||||||
public function testGetArray()
|
|
||||||
{
|
|
||||||
$result = [
|
|
||||||
"title" => "The Rangitaki logo 2",
|
|
||||||
"date" => "24 July 2015",
|
|
||||||
"tags" => array(
|
|
||||||
"design", "artwork", "logo",
|
|
||||||
),
|
|
||||||
"author" => "",
|
|
||||||
"text" => "
|
|
||||||
This is the official Rangitaki logo.
|
|
||||||
|
|
||||||
![The Rangitaki logo](media/example.png)
|
|
||||||
|
|
||||||
It is saved in the example blog directory.
|
|
||||||
",
|
|
||||||
];
|
|
||||||
|
|
||||||
$this->assertEquals(
|
|
||||||
$result,
|
|
||||||
ArticleGenerator::getArray("articles/example/", "2015-07-25-example.md")
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
public function testGetText()
|
|
||||||
{
|
|
||||||
$result = "
|
|
||||||
This is the official Rangitaki logo.
|
|
||||||
|
|
||||||
![The Rangitaki logo](media/example.png)
|
|
||||||
|
|
||||||
It is saved in the example blog directory.
|
|
||||||
";
|
|
||||||
$this->assertEquals(
|
|
||||||
$result,
|
|
||||||
ArticleGenerator::getText("articles/example/", "2015-07-25-example.md")
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
public function testGetAuthor()
|
|
||||||
{
|
|
||||||
$result = "";
|
|
||||||
$this->assertEquals(
|
|
||||||
$result,
|
|
||||||
ArticleGenerator::getAuthor("articles/example/", "2015-07-25-example.md")
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
public function testGetSummary()
|
|
||||||
{
|
|
||||||
$result = "This is the official Rangitaki logo.";
|
|
||||||
$this->assertEquals(
|
|
||||||
$result,
|
|
||||||
ArticleGenerator::getSummary("articles/example/", "2015-07-25-example.md")
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
public function testGetTags()
|
|
||||||
{
|
|
||||||
$result = [ "design", "artwork", "logo" ];
|
|
||||||
$this->assertEquals(
|
|
||||||
$result,
|
|
||||||
ArticleGenerator::getTags("articles/example/", "2015-07-25-example.md")
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
public function testGetDate()
|
|
||||||
{
|
|
||||||
$result = "24 July 2015";
|
|
||||||
$this->assertEquals(
|
|
||||||
$result,
|
|
||||||
ArticleGenerator::getDate("articles/example/", "2015-07-25-example.md")
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
public function testGetTitle()
|
|
||||||
{
|
|
||||||
$result = "The Rangitaki logo 2";
|
|
||||||
$this->assertEquals(
|
|
||||||
$result,
|
|
||||||
ArticleGenerator::getTitle("articles/example/", "2015-07-25-example.md")
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,39 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
use PHPUnit\Framework\TestCase;
|
|
||||||
|
|
||||||
require 'res/php/BlogListGenerator.php';
|
|
||||||
use mmk2410\rbe\BlogListGenerator\BlogListGenerator as BlogListGenerator;
|
|
||||||
|
|
||||||
class BlogListGeneratorTest extends TestCase
|
|
||||||
{
|
|
||||||
public function testListBlog()
|
|
||||||
{
|
|
||||||
$this->assertEquals("<a class='nav-item' href='./?blog=example'>Example</a>",
|
|
||||||
BlogListGenerator::listBlog("./blogs/", "example.md", "Example Blog")
|
|
||||||
);
|
|
||||||
$this->assertEquals("<a class='nav-item' href='https://mmk2410.org/rangitaki/docs/'>Docs</a>",
|
|
||||||
BlogListGenerator::listBlog("./blogs/", "external.md", "Example Blog")
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
public function testGetName()
|
|
||||||
{
|
|
||||||
$this->assertEquals("Example", BlogListGenerator::getName("blogs/example.md"));
|
|
||||||
}
|
|
||||||
|
|
||||||
public function testGetArticleAmount()
|
|
||||||
{
|
|
||||||
$this->assertEquals(5, BlogListGenerator::getArticleAmount("example"));
|
|
||||||
}
|
|
||||||
|
|
||||||
public function testGetExternaleLink()
|
|
||||||
{
|
|
||||||
$this->assertEquals(null,
|
|
||||||
BlogListGenerator::getExternalLink("example.md", '.')
|
|
||||||
);
|
|
||||||
$this->assertEquals("https://mmk2410.org/rangitaki/docs/",
|
|
||||||
BlogListGenerator::getExternalLink("external.md", '.')
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,83 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
namespace mmk2410\rbe\tests\config;
|
|
||||||
|
|
||||||
require_once 'PHPUnit/Autoload.php';
|
|
||||||
require 'res/php/Config.php';
|
|
||||||
|
|
||||||
use \mmk2410\rbe\config\Config as Config;
|
|
||||||
|
|
||||||
class ConfigTest extends \PHPUnit_Framework_TestCase
|
|
||||||
{
|
|
||||||
|
|
||||||
public function testGetConfig()
|
|
||||||
{
|
|
||||||
$config = [
|
|
||||||
"blog" => array(
|
|
||||||
"title" => "Example Blog",
|
|
||||||
"author" => "John",
|
|
||||||
"description" => "A short description of your blog",
|
|
||||||
"home" => "on",
|
|
||||||
"homeurl" => "../",
|
|
||||||
"homename" => "Home",
|
|
||||||
"mainname" => "",
|
|
||||||
"intro" => "on",
|
|
||||||
"disqus" => "rangitaki",
|
|
||||||
"analytics" => "",
|
|
||||||
"footer" =>
|
|
||||||
"Rangitaki 2016 <a href=\"https://gitlab.com/mmk2410/rangitaki\" target=\"blank\">\n gitlab.com/mmk2410/rangitaki</a>", "url" => "https://example.com/blog/",
|
|
||||||
),
|
|
||||||
"design" => array(
|
|
||||||
"fab" => "on",
|
|
||||||
"drawer" => "on",
|
|
||||||
"theme" => "material-light",
|
|
||||||
"pagination" => 0,
|
|
||||||
"favicon" => "http://example.com/res/img/favicon.png",
|
|
||||||
),
|
|
||||||
"rcc" => array(
|
|
||||||
"rcc" => "on",
|
|
||||||
"api" => "on",
|
|
||||||
),
|
|
||||||
"language" => "en",
|
|
||||||
];
|
|
||||||
|
|
||||||
$configParser = new Config("./config.yaml", "./vendor/autoload.php");
|
|
||||||
$this->assertEquals($config, $configParser->getConfig());
|
|
||||||
}
|
|
||||||
|
|
||||||
public function testWriteReadConfig()
|
|
||||||
{
|
|
||||||
$changedConfig = [
|
|
||||||
"blog" => array(
|
|
||||||
"title" => "Examples Blog",
|
|
||||||
"author" => "Wilson O'Sullivan",
|
|
||||||
"description" => "A long description of your blog",
|
|
||||||
"home" => "on",
|
|
||||||
"homeurl" => "../",
|
|
||||||
"homename" => "Exit",
|
|
||||||
"mainname" => "",
|
|
||||||
"intro" => "on",
|
|
||||||
"disqus" => "",
|
|
||||||
"analytics" => "",
|
|
||||||
"footer" =>
|
|
||||||
"pBlog 1102 <a href=\"https://gitlab.com/mmk2410/rangitaki\" target=\"blank\">
|
|
||||||
\n gitlab.com/mmk2410/rangitaki</a>", "url" => "https://example.com/blog/",
|
|
||||||
),
|
|
||||||
"design" => array(
|
|
||||||
"fab" => "off",
|
|
||||||
"drawer" => "off",
|
|
||||||
"theme" => "material-dark",
|
|
||||||
"pagination" => "-1",
|
|
||||||
"favicon" => "http://sample.com/res/img/favicon.png",
|
|
||||||
),
|
|
||||||
"rcc" => array(
|
|
||||||
"rcc" => "on",
|
|
||||||
"api" => "off",
|
|
||||||
),
|
|
||||||
"language" => "en",
|
|
||||||
];
|
|
||||||
$configParser = new Config("/tmp/config-test.yaml", "./vendor/autoload.php");
|
|
||||||
$configParser->writeConfig($changedConfig);
|
|
||||||
$this->assertEquals($changedConfig, $configParser->getConfig());
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,3 +0,0 @@
|
||||||
body{font-family:"Fira Sans",sans-serif;background:#f0f0f0;color:#383838;margin:130px 0 0}::selection,::-moz-selection{color:#f0f0f0;background-color:#4CAF50}.header{height:55px;background-color:#4CAF50;position:fixed;box-shadow:2px 0 2px 2px rgba(62,62,62,0.45)}.title{line-height:55px;color:#fff;position:absolute;left:0;margin-left:calc(20% + 24px)}.title>a{color:#fff;text-decoration:none}.fadeout{height:55px;background:-moz-linear-gradient(left, rgba(30,87,153,0) 0%, #4CAF50 100%);background:-webkit-linear-gradient(left, rgba(30,87,153,0) 0%, #4CAF50 100%);background:-o-linear-gradient(left, rgba(30,87,153,0) 0%, #4CAF50 100%);background:-ms-linear-gradient(left, rgba(30,87,153,0) 0%, #4CAF50 100%);background:linear-gradient(to right, rgba(30,87,153,0) 0%, #4CAF50 100%)}.nav-img{padding:14px 19px}.nav{background-color:#fff;border-right:1px solid #e0e0e0}.nav-item,.nav-item-static{color:#383838}.nav-item{font-weight:600}.nav-item:hover{color:#4CAF50}.nav-item:active{background-color:#e2e2e2}.divider{border-bottom:1px solid #e0e0e0}.card{background:none;border-radius:0;box-shadow:none;margin:0 20% 100px;width:auto}.card a{color:#4CAF50;text-decoration:none;border-bottom:1px solid transparent;transition:border-bottom-color 150ms ease-in-out 100ms}.card a:hover{border-bottom-color:#4CAF50}.headline{font-size:30px;line-height:50px;color:#383838 !important;text-decoration:none;border-bottom:none !important}.headline:hover{color:#4CAF50 !important}.date{font-size:13px}.articletext{margin-top:30px;font-size:16px;line-height:30px}.author,.tag{font-size:13px}.fab{background-color:#4CAF50;box-shadow:0 1px 1.5px 1.5px rgba(62,62,62,0.3)}.subfab{background-color:#fff;box-shadow:0 1px 1.5px 1.5px rgba(62,62,62,0.3)}.button{color:#4CAF50;border-bottom:1px solid transparent;margin:0;min-width:0;padding:0;line-height:16px;height:16px;transition-property:border-bottom-color;transition-delay:50ms;transition-duration:125ms;transition-timing-function:ease;-moz-transition-property:border-bottom-color;-moz-transition-delay:50ms;-moz-transition-duration:125ms;-moz-transition-timing-function:ease;-webkit-transition-property:border-bottom-color;-webkit-transition-delay:50ms;-webkit-transition-duration:125ms;-webkit-transition-timing-function:ease}.button:hover{border-bottom-color:#4CAF50}.pag_prev{float:left}.button:last-child{float:none}.footer{text-align:center;height:60px;background-color:#2D2D2D;line-height:60px;width:100%;color:#fff}.footer a{color:#fff;text-decoration:none;border-bottom:1px solid transparent}.footer a:hover{border-bottom-color:#fff}.hljs{background:none}@media screen and (min-width: 1440px){.title{margin-left:calc(20% - 40px)}.nav{padding-top:55px}}@media screen and (max-width: 800px){body{margin-top:80px}.title{margin-left:20%}.card{margin:0 5% 100px}}
|
|
||||||
|
|
||||||
/*# sourceMappingURL=nextDESIGN.css.map */
|
|
File diff suppressed because one or more lines are too long
|
@ -1,70 +0,0 @@
|
||||||
#!/bin/bash
|
|
||||||
# Update script for Rangitaki from version 1.4.0 to 1.4.1
|
|
||||||
|
|
||||||
version="1.4.1"
|
|
||||||
new="./rbe-new"
|
|
||||||
|
|
||||||
echo -n "Downloading version $version from GitLab... "
|
|
||||||
git clone -q https://gitlab.com/mmk2410/rangitaki.git "$new"
|
|
||||||
|
|
||||||
if [[ $1 == "--debug" ]]; then
|
|
||||||
cd $new
|
|
||||||
git checkout master
|
|
||||||
cd ../
|
|
||||||
fi
|
|
||||||
echo "done"
|
|
||||||
|
|
||||||
echo -n "Updating ressources... "
|
|
||||||
rm -rf ./res/
|
|
||||||
mv $new/res/ ./
|
|
||||||
echo "done"
|
|
||||||
|
|
||||||
echo -n "Updating binaries... "
|
|
||||||
rm -rf ./bin
|
|
||||||
mv $new/bin/ ./
|
|
||||||
echo "done"
|
|
||||||
|
|
||||||
echo -n "Updating source files... "
|
|
||||||
rm -rf ./src
|
|
||||||
mv $new/src/ ./
|
|
||||||
echo "done"
|
|
||||||
|
|
||||||
echo -n "Updating RCC... "
|
|
||||||
rm -rf ./rcc
|
|
||||||
mv $new/rcc ./
|
|
||||||
rm ./rcc/password.php
|
|
||||||
echo "done"
|
|
||||||
|
|
||||||
echo -n "Updating core... "
|
|
||||||
rm ./index.php
|
|
||||||
mv $new/index.php ./
|
|
||||||
echo "done"
|
|
||||||
|
|
||||||
echo -n "Updating npm... "
|
|
||||||
mv $new/package.json ./
|
|
||||||
echo "done"
|
|
||||||
|
|
||||||
echo -n "Updating Changelog... "
|
|
||||||
|
|
||||||
if [ -f ./CHANGELOG.txt ]; then
|
|
||||||
rm CHANGELOG.txt
|
|
||||||
fi
|
|
||||||
|
|
||||||
mv $new/CHANGELOG.md ./
|
|
||||||
echo "done"
|
|
||||||
|
|
||||||
if [[ $1 != "--debug" ]]; then
|
|
||||||
echo -n "Cleaning up... "
|
|
||||||
rm -rf $new
|
|
||||||
echo "done"
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [ -d "./update-scripts" ]; then
|
|
||||||
echo -n "Remove obsolete update scripts folder... "
|
|
||||||
rm -rf "./update-scripts"
|
|
||||||
echo "done"
|
|
||||||
fi
|
|
||||||
|
|
||||||
echo "$version" > ./VERSION
|
|
||||||
|
|
||||||
echo "Your Rangitaki installation is updated to version $version"
|
|
|
@ -1,48 +0,0 @@
|
||||||
#!/bin/bash
|
|
||||||
# Update script for Rangitaki from version 1.4.0 to 1.4.1
|
|
||||||
|
|
||||||
version="1.4.2"
|
|
||||||
new="./rbe-new"
|
|
||||||
|
|
||||||
echo -n "Downloading version $version from GitLab... "
|
|
||||||
git clone -q https://gitlab.com/mmk2410/rangitaki.git "$new"
|
|
||||||
|
|
||||||
if [[ $1 == "--debug" ]]; then
|
|
||||||
cd $new
|
|
||||||
git checkout master
|
|
||||||
cd ../
|
|
||||||
fi
|
|
||||||
echo "done"
|
|
||||||
|
|
||||||
echo -n "Updating RCC... "
|
|
||||||
mv ./rcc/password.php ./
|
|
||||||
rm -rf ./rcc
|
|
||||||
mv $new/rcc ./
|
|
||||||
rm ./rcc/password.php
|
|
||||||
mv ./password.php ./rcc/
|
|
||||||
echo "done"
|
|
||||||
|
|
||||||
echo -n "Updating Changelog... "
|
|
||||||
|
|
||||||
if [ -f ./CHANGELOG.txt ]; then
|
|
||||||
rm CHANGELOG.txt
|
|
||||||
fi
|
|
||||||
|
|
||||||
mv $new/CHANGELOG.md ./
|
|
||||||
echo "done"
|
|
||||||
|
|
||||||
if [[ $1 != "--debug" ]]; then
|
|
||||||
echo -n "Cleaning up... "
|
|
||||||
rm -rf $new
|
|
||||||
echo "done"
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [ -d "./update-scripts" ]; then
|
|
||||||
echo -n "Remove obsolete update scripts folder... "
|
|
||||||
rm -rf "./update-scripts"
|
|
||||||
echo "done"
|
|
||||||
fi
|
|
||||||
|
|
||||||
echo "$version" > ./VERSION
|
|
||||||
|
|
||||||
echo "Your Rangitaki installation is updated to version $version"
|
|
|
@ -1,78 +0,0 @@
|
||||||
#!/bin/bash
|
|
||||||
# Update script for Rangitaki from version 1.4.2 to 1.4.3
|
|
||||||
# Also works from 1.4.0 to 1.4.3
|
|
||||||
|
|
||||||
version="1.4.3"
|
|
||||||
new="./rbe-new"
|
|
||||||
|
|
||||||
echo -n "Downloading version $version from GitLab... "
|
|
||||||
git clone -q https://gitlab.com/mmk2410/rangitaki.git "$new"
|
|
||||||
|
|
||||||
if [[ $1 == "--debug" ]]; then
|
|
||||||
cd $new
|
|
||||||
git checkout -q master
|
|
||||||
cd ../
|
|
||||||
fi
|
|
||||||
echo "done"
|
|
||||||
|
|
||||||
echo -n "Updating ressources... "
|
|
||||||
rm -rf ./res/
|
|
||||||
mv $new/res/ ./
|
|
||||||
echo "done"
|
|
||||||
|
|
||||||
echo -n "Updating source files... "
|
|
||||||
rm ./src/coffee/app.coffee
|
|
||||||
mv $new/src/coffee/app.coffee ./src/coffee/
|
|
||||||
mv $new/src/sass-themes/nextDESIGN.sass ./src/sass-themes/
|
|
||||||
echo "done"
|
|
||||||
|
|
||||||
echo -n "Updating RCC... "
|
|
||||||
rm -rf ./rcc
|
|
||||||
mv $new/rcc ./
|
|
||||||
rm ./rcc/password.php
|
|
||||||
echo "done"
|
|
||||||
|
|
||||||
echo -n "Updating core... "
|
|
||||||
rm ./index.php
|
|
||||||
mv $new/index.php ./
|
|
||||||
echo "done"
|
|
||||||
|
|
||||||
echo -n "Updating binaries... "
|
|
||||||
rm -rf ./bin
|
|
||||||
mv $new/bin/ ./
|
|
||||||
echo "done"
|
|
||||||
|
|
||||||
echo -n "Updating themes... "
|
|
||||||
rm ./themes/material-light.css*
|
|
||||||
rm ./themes/material-dark.css*
|
|
||||||
rm ./themes/background-img.css*
|
|
||||||
mv $new/themes/* ./themes/
|
|
||||||
echo "done"
|
|
||||||
|
|
||||||
echo -n "Updating npm... "
|
|
||||||
mv $new/package.json ./
|
|
||||||
echo "done"
|
|
||||||
|
|
||||||
echo -n "Updating Changelog... "
|
|
||||||
|
|
||||||
if [ -f ./CHANGELOG.txt ]; then
|
|
||||||
rm CHANGELOG.txt
|
|
||||||
fi
|
|
||||||
|
|
||||||
mv $new/CHANGELOG.md ./
|
|
||||||
echo "done"
|
|
||||||
|
|
||||||
echo -n "Cleaning up... "
|
|
||||||
if [[ $1 != "--debug" ]]; then
|
|
||||||
echo -n "Cleaning up... "
|
|
||||||
rm -rf $new
|
|
||||||
echo "done"
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [ -d "./update-scripts" ]; then
|
|
||||||
echo -n "Remove obsolete update scripts folder... "
|
|
||||||
rm -rf "./update-scripts"
|
|
||||||
echo "done"
|
|
||||||
fi
|
|
||||||
|
|
||||||
echo "Your Rangitaki installation is updated to version $version"
|
|
|
@ -1,51 +0,0 @@
|
||||||
#!/bin/bash
|
|
||||||
# Update script for Rangitaki from version 1.4.3 to 1.4.4
|
|
||||||
|
|
||||||
version="1.4.4"
|
|
||||||
new="./rbe-new"
|
|
||||||
|
|
||||||
echo -n "Downloading version $version from GitLab... "
|
|
||||||
git clone -q https://gitlab.com/mmk2410/rangitaki.git "$new"
|
|
||||||
|
|
||||||
if [[ $1 == "--debug" ]]; then
|
|
||||||
cd $new
|
|
||||||
git checkout -q master
|
|
||||||
cd ../
|
|
||||||
fi
|
|
||||||
echo "done"
|
|
||||||
|
|
||||||
echo -n "Updating RCC... "
|
|
||||||
mv ./rcc/password.php ./password.php
|
|
||||||
rm -rf ./rcc/
|
|
||||||
mv $new/rcc ./
|
|
||||||
rm ./rcc/password.php
|
|
||||||
mv ./password.php ./rcc/password.php
|
|
||||||
echo "done"
|
|
||||||
|
|
||||||
echo -n "Updating npm... "
|
|
||||||
mv $new/package.json ./
|
|
||||||
echo "done"
|
|
||||||
|
|
||||||
echo -n "Updating Changelog... "
|
|
||||||
|
|
||||||
if [ -f ./CHANGELOG.txt ]; then
|
|
||||||
rm CHANGELOG.txt
|
|
||||||
fi
|
|
||||||
|
|
||||||
mv $new/CHANGELOG.md ./
|
|
||||||
echo "done"
|
|
||||||
|
|
||||||
echo -n "Cleaning up... "
|
|
||||||
if [[ $1 != "--debug" ]]; then
|
|
||||||
echo -n "Cleaning up... "
|
|
||||||
rm -rf $new
|
|
||||||
echo "done"
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [ -d "./update-scripts" ]; then
|
|
||||||
echo -n "Remove obsolete update scripts folder... "
|
|
||||||
rm -rf "./update-scripts"
|
|
||||||
echo "done"
|
|
||||||
fi
|
|
||||||
|
|
||||||
echo "Your Rangitaki installation is updated to version $version"
|
|
|
@ -1,84 +0,0 @@
|
||||||
#!/bin/bash
|
|
||||||
# Update script for Rangitaki from version 1.4.4 to 1.5.0
|
|
||||||
|
|
||||||
version="1.5.0"
|
|
||||||
new="./rbe-new"
|
|
||||||
|
|
||||||
echo -n "Downloading version $version from GitLab... "
|
|
||||||
git clone -q https://gitlab.com/mmk2410/rangitaki.git "$new"
|
|
||||||
|
|
||||||
if [[ $1 == "--debug" ]]; then
|
|
||||||
cd $new
|
|
||||||
git checkout -q master
|
|
||||||
cd ../
|
|
||||||
fi
|
|
||||||
echo "done"
|
|
||||||
|
|
||||||
echo -n "Updating ressources... "
|
|
||||||
rm -rf ./res/
|
|
||||||
mv $new/res/ ./
|
|
||||||
echo "done"
|
|
||||||
|
|
||||||
echo -n "Updating languages... "
|
|
||||||
rm -rf ./lang/de.php
|
|
||||||
rm -rf ./lang/en.php
|
|
||||||
mv $new/lang/* ./lang/
|
|
||||||
echo "done"
|
|
||||||
|
|
||||||
echo -n "Updating source files... "
|
|
||||||
rm ./src/sass/rangitaki.sass
|
|
||||||
mv $new/src/sass/rangitaki.sass ./src/sass/
|
|
||||||
echo "done"
|
|
||||||
|
|
||||||
echo -n "Updating core... "
|
|
||||||
rm ./index.php
|
|
||||||
mv $new/index.php ./
|
|
||||||
echo "done"
|
|
||||||
|
|
||||||
echo -n "Updating binaries... "
|
|
||||||
rm -rf ./bin
|
|
||||||
mv $new/bin/ ./
|
|
||||||
echo "done"
|
|
||||||
|
|
||||||
echo -n "Updating themes... "
|
|
||||||
rm ./themes/material-light.css*
|
|
||||||
rm ./themes/material-dark.css*
|
|
||||||
rm ./themes/background-img.css*
|
|
||||||
rm ./themes/nextDESIGN.css*
|
|
||||||
mv $new/themes/* ./themes/
|
|
||||||
echo "done"
|
|
||||||
|
|
||||||
echo -n "Updating npm... "
|
|
||||||
mv $new/package.json ./
|
|
||||||
echo "done"
|
|
||||||
|
|
||||||
echo -n 'Updating config script... '
|
|
||||||
echo "social:" >> ./config.yaml
|
|
||||||
echo " twitter: ''" >> ./config.yaml
|
|
||||||
sed -i "s/design:/design:\n excerpt: 'off'/" config.yaml
|
|
||||||
echo "done"
|
|
||||||
|
|
||||||
echo -n "Updating Changelog... "
|
|
||||||
|
|
||||||
if [ -f ./CHANGELOG.txt ]; then
|
|
||||||
rm CHANGELOG.txt
|
|
||||||
fi
|
|
||||||
|
|
||||||
mv $new/CHANGELOG.md ./
|
|
||||||
echo "done"
|
|
||||||
|
|
||||||
echo -n "Cleaning up... "
|
|
||||||
if [[ $1 != "--debug" ]]; then
|
|
||||||
echo -n "Cleaning up... "
|
|
||||||
rm -rf $new
|
|
||||||
echo "done"
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [ -d "./update-scripts" ]; then
|
|
||||||
echo -n "Remove obsolete update scripts folder... "
|
|
||||||
rm -rf "./update-scripts"
|
|
||||||
echo "done"
|
|
||||||
fi
|
|
||||||
|
|
||||||
echo "Your Rangitaki installation is updated to version $version"
|
|
||||||
echo "Run php ./bin/init.php to use set the values for the new features."
|
|
2
vendor/autoload.php
vendored
2
vendor/autoload.php
vendored
|
@ -2,6 +2,6 @@
|
||||||
|
|
||||||
// autoload.php @generated by Composer
|
// autoload.php @generated by Composer
|
||||||
|
|
||||||
require_once __DIR__ . '/composer/autoload_real.php';
|
require_once __DIR__ . '/composer' . '/autoload_real.php';
|
||||||
|
|
||||||
return ComposerAutoloaderInitd1db2574a85c0ba6f142743249ba228f::getLoader();
|
return ComposerAutoloaderInitd1db2574a85c0ba6f142743249ba228f::getLoader();
|
||||||
|
|
5
vendor/bshaffer/oauth2-server-php/.gitignore
vendored
Normal file
5
vendor/bshaffer/oauth2-server-php/.gitignore
vendored
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
# Test Files #
|
||||||
|
test/config/test.sqlite
|
||||||
|
vendor
|
||||||
|
composer.lock
|
||||||
|
.idea
|
25
vendor/bshaffer/oauth2-server-php/.travis.yml
vendored
Normal file
25
vendor/bshaffer/oauth2-server-php/.travis.yml
vendored
Normal file
|
@ -0,0 +1,25 @@
|
||||||
|
language: php
|
||||||
|
sudo: false
|
||||||
|
php:
|
||||||
|
- 5.3
|
||||||
|
- 5.4
|
||||||
|
- 5.5
|
||||||
|
- 5.6
|
||||||
|
- hhvm
|
||||||
|
env:
|
||||||
|
global:
|
||||||
|
- SKIP_MONGO_TESTS=1
|
||||||
|
- secure: Bc5ZqvZ1YYpoPZNNuU2eCB8DS6vBYrAdfBtTenBs5NSxzb+Vjven4kWakbzaMvZjb/Ib7Uph7DGuOtJXpmxnvBXPLd707LZ89oFWN/yqQlZKCcm8iErvJCB5XL+/ONHj2iPdR242HJweMcat6bMCwbVWoNDidjtWMH0U2mYFy3M=
|
||||||
|
- secure: R3bXlymyFiY2k2jf7+fv/J8i34wtXTkmD4mCr5Ps/U+vn9axm2VtvR2Nj+r7LbRjn61gzFE/xIVjYft/wOyBOYwysrfriydrnRVS0owh6y+7EyOyQWbRX11vVQMf8o31QCQE5BY58V5AJZW3MjoOL0FVlTgySJiJvdw6Pv18v+E=
|
||||||
|
services:
|
||||||
|
- mongodb
|
||||||
|
- redis-server
|
||||||
|
- cassandra
|
||||||
|
before_script:
|
||||||
|
- psql -c 'create database oauth2_server_php;' -U postgres
|
||||||
|
- composer require predis/predis:dev-master
|
||||||
|
- composer require thobbs/phpcassa:dev-master
|
||||||
|
- composer require 'aws/aws-sdk-php:~2.8'
|
||||||
|
- composer require 'firebase/php-jwt:~2.2'
|
||||||
|
after_script:
|
||||||
|
- php test/cleanup.php
|
165
vendor/bshaffer/oauth2-server-php/CHANGELOG.md
vendored
Normal file
165
vendor/bshaffer/oauth2-server-php/CHANGELOG.md
vendored
Normal file
|
@ -0,0 +1,165 @@
|
||||||
|
CHANGELOG for 1.x
|
||||||
|
=================
|
||||||
|
|
||||||
|
This changelog references the relevant changes (bug and security fixes) done
|
||||||
|
in 1.x minor versions.
|
||||||
|
|
||||||
|
To see the files changed for a given bug, go to https://github.com/bshaffer/oauth2-server-php/issues/### where ### is the bug number
|
||||||
|
To get the diff between two versions, go to https://github.com/bshaffer/oauth2-server-php/compare/v1.0...v1.1
|
||||||
|
To get the diff for a specific change, go to https://github.com/bshaffer/oauth2-server-php/commit/XXX where XXX is the change hash
|
||||||
|
|
||||||
|
* 1.8.0 (2015-09-18)
|
||||||
|
|
||||||
|
PR: https://github.com/bshaffer/oauth2-server-php/pull/643
|
||||||
|
|
||||||
|
* bug #594 - adds jti
|
||||||
|
* bug #598 - fixes lifetime configurations for JWTs
|
||||||
|
* bug #634 - fixes travis builds, upgrade to containers
|
||||||
|
* bug #586 - support for revoking tokens
|
||||||
|
* bug #636 - Adds FirebaseJWT bridge
|
||||||
|
* bug #639 - Mongo HHVM compatibility
|
||||||
|
|
||||||
|
* 1.7.0 (2015-04-23)
|
||||||
|
|
||||||
|
PR: https://github.com/bshaffer/oauth2-server-php/pull/572
|
||||||
|
|
||||||
|
* bug #500 - PDO fetch mode changed from FETCH_BOTH to FETCH_ASSOC
|
||||||
|
* bug #508 - Case insensitive for Bearer token header name ba716d4
|
||||||
|
* bug #512 - validateRedirectUri is now public
|
||||||
|
* bug #530 - Add PublicKeyInterface, UserClaimsInterface to Cassandra Storage
|
||||||
|
* bug #505 - DynamoDB storage fixes
|
||||||
|
* bug #556 - adds "code id_token" return type to openid connect
|
||||||
|
* bug #563 - Include "issuer" config key for JwtAccessToken
|
||||||
|
* bug #564 - Fixes JWT vulnerability
|
||||||
|
* bug #571 - Added unset_refresh_token_after_use option
|
||||||
|
|
||||||
|
* 1.6 (2015-01-16)
|
||||||
|
|
||||||
|
PR: https://github.com/bshaffer/oauth2-server-php/pull/496
|
||||||
|
|
||||||
|
* bug 437 - renames CryptoToken to JwtAccessToken / use_crypto_tokens to use_jwt_access_tokens
|
||||||
|
* bug 447 - Adds a Couchbase storage implementation
|
||||||
|
* bug 460 - Rename JWT claims to match spec
|
||||||
|
* bug 470 - order does not matter for multi-valued response types
|
||||||
|
* bug 471 - Make validateAuthorizeRequest available for POST in addition to GET
|
||||||
|
* bug 475 - Adds JTI table definitiion
|
||||||
|
* bug 481 - better randomness for generating access tokens
|
||||||
|
* bug 480 - Use hash_equals() for signature verification (prevents remote timing attacks)
|
||||||
|
* bugs 489, 491, 498 - misc other fixes
|
||||||
|
|
||||||
|
* 1.5 (2014-08-27)
|
||||||
|
|
||||||
|
PR: https://github.com/bshaffer/oauth2-server-php/pull/446
|
||||||
|
|
||||||
|
* bug #399 - Add DynamoDB Support
|
||||||
|
* bug #404 - renamed error name for malformed/expired tokens
|
||||||
|
* bug #412 - Openid connect: fixes for claims with more than one scope / Add support for the prompt parameter ('consent' and 'none')
|
||||||
|
* bug #411 - fixes xml output
|
||||||
|
* bug #413 - fixes invalid format error
|
||||||
|
* bug #401 - fixes code standards / whitespace
|
||||||
|
* bug #354 - bundles PDO SQL with the library
|
||||||
|
* [BC] bug #397 - refresh tokens should not be encrypted
|
||||||
|
* bug #423 - makes "scope" optional for refresh token storage
|
||||||
|
|
||||||
|
* 1.4 (2014-06-12)
|
||||||
|
|
||||||
|
PR: https://github.com/bshaffer/oauth2-server-php/pull/392
|
||||||
|
|
||||||
|
* bug #189 Storage\PDO - allows DSN string in constructor
|
||||||
|
* bug #233 Bearer Tokens - allows token in request body for PUT requests
|
||||||
|
* bug #346 Fixes open_basedir warning
|
||||||
|
* bug #351 Adds OpenID Connect support
|
||||||
|
* bug #355 Adds php 5.6 and HHVM to travis.ci testing
|
||||||
|
* [BC] bug #358 Adds `getQuerystringIdentifier()` to the GrantType interface
|
||||||
|
* bug #363 Encryption\JWT - Allows for subclassing JWT Headers
|
||||||
|
* bug #349 Bearer Tokens - adds requestHasToken method for when access tokens are optional
|
||||||
|
* bug #301 Encryption\JWT - fixes urlSafeB64Encode(): ensures newlines are replaced as expected
|
||||||
|
* bug #323 ResourceController - client_id is no longer required to be returned when calling getAccessToken
|
||||||
|
* bug #367 Storage\PDO - adds Postgres support
|
||||||
|
* bug #368 Access Tokens - use mcrypt_create_iv or openssl_random_pseudo_bytes to create token string
|
||||||
|
* bug #376 Request - allows case insensitive headers
|
||||||
|
* bug #384 Storage\PDO - can pass in PDO options in constructor of PDO storage
|
||||||
|
* misc fixes #361, #292, #373, #374, #379, #396
|
||||||
|
* 1.3 (2014-02-27)
|
||||||
|
|
||||||
|
PR: https://github.com/bshaffer/oauth2-server-php/pull/325
|
||||||
|
|
||||||
|
* bug #311 adds cassandra storage
|
||||||
|
* bug #298 fixes response code for user credentials grant type
|
||||||
|
* bug #318 adds 'use_crypto_tokens' config to Server class for better DX
|
||||||
|
* [BC] bug #320 pass client_id to getDefaultScope
|
||||||
|
* bug #324 better feedback when running tests
|
||||||
|
* bug #335 adds support for non-expiring refresh tokens
|
||||||
|
* bug #333 fixes Pdo storage for getClientKey
|
||||||
|
* bug #336 fixes Redis storage for expireAuthorizationCode
|
||||||
|
|
||||||
|
* 1.3 (2014-02-27)
|
||||||
|
|
||||||
|
PR: https://github.com/bshaffer/oauth2-server-php/pull/325
|
||||||
|
|
||||||
|
* bug #311 adds cassandra storage
|
||||||
|
* bug #298 fixes response code for user credentials grant type
|
||||||
|
* bug #318 adds 'use_crypto_tokens' config to Server class for better DX
|
||||||
|
* bug #320 pass client_id to getDefaultScope
|
||||||
|
* bug #324 better feedback when running tests
|
||||||
|
* bug #335 adds support for non-expiring refresh tokens
|
||||||
|
* bug #333 fixes Pdo storage for getClientKey
|
||||||
|
* bug #336 fixes Redis storage for expireAuthorizationCode
|
||||||
|
|
||||||
|
* 1.2 (2014-01-03)
|
||||||
|
|
||||||
|
PR: https://github.com/bshaffer/oauth2-server-php/pull/288
|
||||||
|
|
||||||
|
* bug #285 changed response header from 200 to 401 when empty token received
|
||||||
|
* bug #286 adds documentation and links to spec for not including error messages when no token is supplied
|
||||||
|
* bug #280 ensures PHP warnings do not get thrown as a result of an invalid argument to $jwt->decode()
|
||||||
|
* bug #279 predis wrong number of arguments
|
||||||
|
* bug #277 Securing JS WebApp client secret w/ password grant type
|
||||||
|
|
||||||
|
* 1.1 (2013-12-17)
|
||||||
|
|
||||||
|
PR: https://github.com/bshaffer/oauth2-server-php/pull/276
|
||||||
|
|
||||||
|
* bug #278 adds refresh token configuration to Server class
|
||||||
|
* bug #274 Supplying a null client_id and client_secret grants API access
|
||||||
|
* bug #244 [MongoStorage] More detailed implementation info
|
||||||
|
* bug #268 Implement jti for JWT Bearer tokens to prevent replay attacks.
|
||||||
|
* bug #266 Removing unused argument to getAccessTokenData
|
||||||
|
* bug #247 Make Bearer token type consistent
|
||||||
|
* bug #253 Fixing CryptoToken refresh token lifetime
|
||||||
|
* bug #246 refactors public key logic to be more intuitive
|
||||||
|
* bug #245 adds support for JSON crypto tokens
|
||||||
|
* bug #230 Remove unused columns in oauth_clients
|
||||||
|
* bug #215 makes Redis Scope Storage obey the same paradigm as PDO
|
||||||
|
* bug #228 removes scope group
|
||||||
|
* bug #227 squelches open basedir restriction error
|
||||||
|
* bug #223 Updated docblocks for RefreshTokenInterface.php
|
||||||
|
* bug #224 Adds protected properties
|
||||||
|
* bug #217 Implement ScopeInterface for PDO, Redis
|
||||||
|
|
||||||
|
* 1.0 (2013-08-12)
|
||||||
|
|
||||||
|
* bug #203 Add redirect\_status_code config param for AuthorizeController
|
||||||
|
* bug #205 ensures unnecessary ? is not set when ** bug
|
||||||
|
* bug #204 Fixed call to LogicException
|
||||||
|
* bug #202 Add explode to checkRestrictedGrant in PDO Storage
|
||||||
|
* bug #197 adds support for 'false' default scope ** bug
|
||||||
|
* bug #192 reference errors and adds tests
|
||||||
|
* bug #194 makes some appropriate properties ** bug
|
||||||
|
* bug #191 passes config to HttpBasic
|
||||||
|
* bug #190 validates client credentials before ** bug
|
||||||
|
* bug #171 Fix wrong redirect following authorization step
|
||||||
|
* bug #187 client_id is now passed to getDefaultScope().
|
||||||
|
* bug #176 Require refresh_token in getRefreshToken response
|
||||||
|
* bug #174 make user\_id not required for refresh_token grant
|
||||||
|
* bug #173 Duplication in JwtBearer Grant
|
||||||
|
* bug #168 user\_id not required for authorization_code grant
|
||||||
|
* bug #133 hardens default security for user object
|
||||||
|
* bug #163 allows redirect\_uri on authorization_code to be NULL in docs example
|
||||||
|
* bug #162 adds getToken on ResourceController for convenience
|
||||||
|
* bug #161 fixes fatal error
|
||||||
|
* bug #163 Invalid redirect_uri handling
|
||||||
|
* bug #156 user\_id in OAuth2\_Storage_AuthorizationCodeInterface::getAuthorizationCode() response
|
||||||
|
* bug #157 Fix for extending access and refresh tokens
|
||||||
|
* bug #154 ResponseInterface: getParameter method is used in the library but not defined in the interface
|
||||||
|
* bug #148 Add more detail to examples in Readme.md
|
21
vendor/bshaffer/oauth2-server-php/LICENSE
vendored
Normal file
21
vendor/bshaffer/oauth2-server-php/LICENSE
vendored
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
The MIT License
|
||||||
|
|
||||||
|
Copyright (c) 2014 Brent Shaffer
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in
|
||||||
|
all copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
THE SOFTWARE.
|
8
vendor/bshaffer/oauth2-server-php/README.md
vendored
Normal file
8
vendor/bshaffer/oauth2-server-php/README.md
vendored
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
oauth2-server-php
|
||||||
|
=================
|
||||||
|
|
||||||
|
[![Build Status](https://travis-ci.org/bshaffer/oauth2-server-php.svg?branch=develop)](https://travis-ci.org/bshaffer/oauth2-server-php)
|
||||||
|
|
||||||
|
[![Total Downloads](https://poser.pugx.org/bshaffer/oauth2-server-php/downloads.png)](https://packagist.org/packages/bshaffer/oauth2-server-php)
|
||||||
|
|
||||||
|
View the [complete documentation](http://bshaffer.github.io/oauth2-server-php-docs/)
|
27
vendor/bshaffer/oauth2-server-php/composer.json
vendored
Normal file
27
vendor/bshaffer/oauth2-server-php/composer.json
vendored
Normal file
|
@ -0,0 +1,27 @@
|
||||||
|
{
|
||||||
|
"name": "bshaffer/oauth2-server-php",
|
||||||
|
"description":"OAuth2 Server for PHP",
|
||||||
|
"keywords":["oauth","oauth2","auth"],
|
||||||
|
"type":"library",
|
||||||
|
"license":"MIT",
|
||||||
|
"authors":[
|
||||||
|
{
|
||||||
|
"name":"Brent Shaffer",
|
||||||
|
"email": "bshafs@gmail.com",
|
||||||
|
"homepage":"http://brentertainment.com"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"homepage": "http://github.com/bshaffer/oauth2-server-php",
|
||||||
|
"require":{
|
||||||
|
"php":">=5.3.9"
|
||||||
|
},
|
||||||
|
"autoload": {
|
||||||
|
"psr-0": { "OAuth2": "src/" }
|
||||||
|
},
|
||||||
|
"suggest": {
|
||||||
|
"predis/predis": "Required to use the Redis storage engine",
|
||||||
|
"thobbs/phpcassa": "Required to use the Cassandra storage engine",
|
||||||
|
"aws/aws-sdk-php": "~2.8 is required to use the DynamoDB storage engine",
|
||||||
|
"firebase/php-jwt": "~2.2 is required to use JWT features"
|
||||||
|
}
|
||||||
|
}
|
25
vendor/bshaffer/oauth2-server-php/phpunit.xml
vendored
Normal file
25
vendor/bshaffer/oauth2-server-php/phpunit.xml
vendored
Normal file
|
@ -0,0 +1,25 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
|
||||||
|
<phpunit backupGlobals="false"
|
||||||
|
backupStaticAttributes="false"
|
||||||
|
colors="true"
|
||||||
|
convertErrorsToExceptions="true"
|
||||||
|
convertNoticesToExceptions="true"
|
||||||
|
convertWarningsToExceptions="true"
|
||||||
|
processIsolation="false"
|
||||||
|
stopOnFailure="false"
|
||||||
|
syntaxCheck="false"
|
||||||
|
bootstrap="test/bootstrap.php"
|
||||||
|
>
|
||||||
|
<testsuites>
|
||||||
|
<testsuite name="Oauth2 Test Suite">
|
||||||
|
<directory>./test/OAuth2/</directory>
|
||||||
|
</testsuite>
|
||||||
|
</testsuites>
|
||||||
|
|
||||||
|
<filter>
|
||||||
|
<whitelist>
|
||||||
|
<directory suffix=".php">./src/OAuth2/</directory>
|
||||||
|
</whitelist>
|
||||||
|
</filter>
|
||||||
|
</phpunit>
|
48
vendor/bshaffer/oauth2-server-php/src/OAuth2/Autoloader.php
vendored
Normal file
48
vendor/bshaffer/oauth2-server-php/src/OAuth2/Autoloader.php
vendored
Normal file
|
@ -0,0 +1,48 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace OAuth2;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Autoloads OAuth2 classes
|
||||||
|
*
|
||||||
|
* @author Brent Shaffer <bshafs at gmail dot com>
|
||||||
|
* @license MIT License
|
||||||
|
*/
|
||||||
|
class Autoloader
|
||||||
|
{
|
||||||
|
private $dir;
|
||||||
|
|
||||||
|
public function __construct($dir = null)
|
||||||
|
{
|
||||||
|
if (is_null($dir)) {
|
||||||
|
$dir = dirname(__FILE__).'/..';
|
||||||
|
}
|
||||||
|
$this->dir = $dir;
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* Registers OAuth2\Autoloader as an SPL autoloader.
|
||||||
|
*/
|
||||||
|
public static function register($dir = null)
|
||||||
|
{
|
||||||
|
ini_set('unserialize_callback_func', 'spl_autoload_call');
|
||||||
|
spl_autoload_register(array(new self($dir), 'autoload'));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handles autoloading of classes.
|
||||||
|
*
|
||||||
|
* @param string $class A class name.
|
||||||
|
*
|
||||||
|
* @return boolean Returns true if the class has been loaded
|
||||||
|
*/
|
||||||
|
public function autoload($class)
|
||||||
|
{
|
||||||
|
if (0 !== strpos($class, 'OAuth2')) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (file_exists($file = $this->dir.'/'.str_replace('\\', '/', $class).'.php')) {
|
||||||
|
require $file;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,15 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace OAuth2\ClientAssertionType;
|
||||||
|
|
||||||
|
use OAuth2\RequestInterface;
|
||||||
|
use OAuth2\ResponseInterface;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Interface for all OAuth2 Client Assertion Types
|
||||||
|
*/
|
||||||
|
interface ClientAssertionTypeInterface
|
||||||
|
{
|
||||||
|
public function validateRequest(RequestInterface $request, ResponseInterface $response);
|
||||||
|
public function getClientId();
|
||||||
|
}
|
123
vendor/bshaffer/oauth2-server-php/src/OAuth2/ClientAssertionType/HttpBasic.php
vendored
Normal file
123
vendor/bshaffer/oauth2-server-php/src/OAuth2/ClientAssertionType/HttpBasic.php
vendored
Normal file
|
@ -0,0 +1,123 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace OAuth2\ClientAssertionType;
|
||||||
|
|
||||||
|
use OAuth2\Storage\ClientCredentialsInterface;
|
||||||
|
use OAuth2\RequestInterface;
|
||||||
|
use OAuth2\ResponseInterface;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Validate a client via Http Basic authentication
|
||||||
|
*
|
||||||
|
* @author Brent Shaffer <bshafs at gmail dot com>
|
||||||
|
*/
|
||||||
|
class HttpBasic implements ClientAssertionTypeInterface
|
||||||
|
{
|
||||||
|
private $clientData;
|
||||||
|
|
||||||
|
protected $storage;
|
||||||
|
protected $config;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param OAuth2\Storage\ClientCredentialsInterface $clientStorage REQUIRED Storage class for retrieving client credentials information
|
||||||
|
* @param array $config OPTIONAL Configuration options for the server
|
||||||
|
* <code>
|
||||||
|
* $config = array(
|
||||||
|
* 'allow_credentials_in_request_body' => true, // whether to look for credentials in the POST body in addition to the Authorize HTTP Header
|
||||||
|
* 'allow_public_clients' => true // if true, "public clients" (clients without a secret) may be authenticated
|
||||||
|
* );
|
||||||
|
* </code>
|
||||||
|
*/
|
||||||
|
public function __construct(ClientCredentialsInterface $storage, array $config = array())
|
||||||
|
{
|
||||||
|
$this->storage = $storage;
|
||||||
|
$this->config = array_merge(array(
|
||||||
|
'allow_credentials_in_request_body' => true,
|
||||||
|
'allow_public_clients' => true,
|
||||||
|
), $config);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function validateRequest(RequestInterface $request, ResponseInterface $response)
|
||||||
|
{
|
||||||
|
if (!$clientData = $this->getClientCredentials($request, $response)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!isset($clientData['client_id'])) {
|
||||||
|
throw new \LogicException('the clientData array must have "client_id" set');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!isset($clientData['client_secret']) || $clientData['client_secret'] == '') {
|
||||||
|
if (!$this->config['allow_public_clients']) {
|
||||||
|
$response->setError(400, 'invalid_client', 'client credentials are required');
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!$this->storage->isPublicClient($clientData['client_id'])) {
|
||||||
|
$response->setError(400, 'invalid_client', 'This client is invalid or must authenticate using a client secret');
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
} elseif ($this->storage->checkClientCredentials($clientData['client_id'], $clientData['client_secret']) === false) {
|
||||||
|
$response->setError(400, 'invalid_client', 'The client credentials are invalid');
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->clientData = $clientData;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getClientId()
|
||||||
|
{
|
||||||
|
return $this->clientData['client_id'];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Internal function used to get the client credentials from HTTP basic
|
||||||
|
* auth or POST data.
|
||||||
|
*
|
||||||
|
* According to the spec (draft 20), the client_id can be provided in
|
||||||
|
* the Basic Authorization header (recommended) or via GET/POST.
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
* A list containing the client identifier and password, for example
|
||||||
|
* @code
|
||||||
|
* return array(
|
||||||
|
* "client_id" => CLIENT_ID, // REQUIRED the client id
|
||||||
|
* "client_secret" => CLIENT_SECRET, // OPTIONAL the client secret (may be omitted for public clients)
|
||||||
|
* );
|
||||||
|
* @endcode
|
||||||
|
*
|
||||||
|
* @see http://tools.ietf.org/html/rfc6749#section-2.3.1
|
||||||
|
*
|
||||||
|
* @ingroup oauth2_section_2
|
||||||
|
*/
|
||||||
|
public function getClientCredentials(RequestInterface $request, ResponseInterface $response = null)
|
||||||
|
{
|
||||||
|
if (!is_null($request->headers('PHP_AUTH_USER')) && !is_null($request->headers('PHP_AUTH_PW'))) {
|
||||||
|
return array('client_id' => $request->headers('PHP_AUTH_USER'), 'client_secret' => $request->headers('PHP_AUTH_PW'));
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($this->config['allow_credentials_in_request_body']) {
|
||||||
|
// Using POST for HttpBasic authorization is not recommended, but is supported by specification
|
||||||
|
if (!is_null($request->request('client_id'))) {
|
||||||
|
/**
|
||||||
|
* client_secret can be null if the client's password is an empty string
|
||||||
|
* @see http://tools.ietf.org/html/rfc6749#section-2.3.1
|
||||||
|
*/
|
||||||
|
|
||||||
|
return array('client_id' => $request->request('client_id'), 'client_secret' => $request->request('client_secret'));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($response) {
|
||||||
|
$message = $this->config['allow_credentials_in_request_body'] ? ' or body' : '';
|
||||||
|
$response->setError(400, 'invalid_client', 'Client credentials were not found in the headers'.$message);
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
383
vendor/bshaffer/oauth2-server-php/src/OAuth2/Controller/AuthorizeController.php
vendored
Normal file
383
vendor/bshaffer/oauth2-server-php/src/OAuth2/Controller/AuthorizeController.php
vendored
Normal file
|
@ -0,0 +1,383 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace OAuth2\Controller;
|
||||||
|
|
||||||
|
use OAuth2\Storage\ClientInterface;
|
||||||
|
use OAuth2\ScopeInterface;
|
||||||
|
use OAuth2\RequestInterface;
|
||||||
|
use OAuth2\ResponseInterface;
|
||||||
|
use OAuth2\Scope;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @see OAuth2\Controller\AuthorizeControllerInterface
|
||||||
|
*/
|
||||||
|
class AuthorizeController implements AuthorizeControllerInterface
|
||||||
|
{
|
||||||
|
private $scope;
|
||||||
|
private $state;
|
||||||
|
private $client_id;
|
||||||
|
private $redirect_uri;
|
||||||
|
private $response_type;
|
||||||
|
|
||||||
|
protected $clientStorage;
|
||||||
|
protected $responseTypes;
|
||||||
|
protected $config;
|
||||||
|
protected $scopeUtil;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param OAuth2\Storage\ClientInterface $clientStorage REQUIRED Instance of OAuth2\Storage\ClientInterface to retrieve client information
|
||||||
|
* @param array $responseTypes OPTIONAL Array of OAuth2\ResponseType\ResponseTypeInterface objects. Valid array
|
||||||
|
* keys are "code" and "token"
|
||||||
|
* @param array $config OPTIONAL Configuration options for the server
|
||||||
|
* <code>
|
||||||
|
* $config = array(
|
||||||
|
* 'allow_implicit' => false, // if the controller should allow the "implicit" grant type
|
||||||
|
* 'enforce_state' => true // if the controller should require the "state" parameter
|
||||||
|
* 'require_exact_redirect_uri' => true, // if the controller should require an exact match on the "redirect_uri" parameter
|
||||||
|
* 'redirect_status_code' => 302, // HTTP status code to use for redirect responses
|
||||||
|
* );
|
||||||
|
* </code>
|
||||||
|
* @param OAuth2\ScopeInterface $scopeUtil OPTIONAL Instance of OAuth2\ScopeInterface to validate the requested scope
|
||||||
|
*/
|
||||||
|
public function __construct(ClientInterface $clientStorage, array $responseTypes = array(), array $config = array(), ScopeInterface $scopeUtil = null)
|
||||||
|
{
|
||||||
|
$this->clientStorage = $clientStorage;
|
||||||
|
$this->responseTypes = $responseTypes;
|
||||||
|
$this->config = array_merge(array(
|
||||||
|
'allow_implicit' => false,
|
||||||
|
'enforce_state' => true,
|
||||||
|
'require_exact_redirect_uri' => true,
|
||||||
|
'redirect_status_code' => 302,
|
||||||
|
), $config);
|
||||||
|
|
||||||
|
if (is_null($scopeUtil)) {
|
||||||
|
$scopeUtil = new Scope();
|
||||||
|
}
|
||||||
|
$this->scopeUtil = $scopeUtil;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function handleAuthorizeRequest(RequestInterface $request, ResponseInterface $response, $is_authorized, $user_id = null)
|
||||||
|
{
|
||||||
|
if (!is_bool($is_authorized)) {
|
||||||
|
throw new \InvalidArgumentException('Argument "is_authorized" must be a boolean. This method must know if the user has granted access to the client.');
|
||||||
|
}
|
||||||
|
|
||||||
|
// We repeat this, because we need to re-validate. The request could be POSTed
|
||||||
|
// by a 3rd-party (because we are not internally enforcing NONCEs, etc)
|
||||||
|
if (!$this->validateAuthorizeRequest($request, $response)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If no redirect_uri is passed in the request, use client's registered one
|
||||||
|
if (empty($this->redirect_uri)) {
|
||||||
|
$clientData = $this->clientStorage->getClientDetails($this->client_id);
|
||||||
|
$registered_redirect_uri = $clientData['redirect_uri'];
|
||||||
|
}
|
||||||
|
|
||||||
|
// the user declined access to the client's application
|
||||||
|
if ($is_authorized === false) {
|
||||||
|
$redirect_uri = $this->redirect_uri ?: $registered_redirect_uri;
|
||||||
|
$this->setNotAuthorizedResponse($request, $response, $redirect_uri, $user_id);
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// build the parameters to set in the redirect URI
|
||||||
|
if (!$params = $this->buildAuthorizeParameters($request, $response, $user_id)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
$authResult = $this->responseTypes[$this->response_type]->getAuthorizeResponse($params, $user_id);
|
||||||
|
|
||||||
|
list($redirect_uri, $uri_params) = $authResult;
|
||||||
|
|
||||||
|
if (empty($redirect_uri) && !empty($registered_redirect_uri)) {
|
||||||
|
$redirect_uri = $registered_redirect_uri;
|
||||||
|
}
|
||||||
|
|
||||||
|
$uri = $this->buildUri($redirect_uri, $uri_params);
|
||||||
|
|
||||||
|
// return redirect response
|
||||||
|
$response->setRedirect($this->config['redirect_status_code'], $uri);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function setNotAuthorizedResponse(RequestInterface $request, ResponseInterface $response, $redirect_uri, $user_id = null)
|
||||||
|
{
|
||||||
|
$error = 'access_denied';
|
||||||
|
$error_message = 'The user denied access to your application';
|
||||||
|
$response->setRedirect($this->config['redirect_status_code'], $redirect_uri, $this->state, $error, $error_message);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* We have made this protected so this class can be extended to add/modify
|
||||||
|
* these parameters
|
||||||
|
*/
|
||||||
|
protected function buildAuthorizeParameters($request, $response, $user_id)
|
||||||
|
{
|
||||||
|
// @TODO: we should be explicit with this in the future
|
||||||
|
$params = array(
|
||||||
|
'scope' => $this->scope,
|
||||||
|
'state' => $this->state,
|
||||||
|
'client_id' => $this->client_id,
|
||||||
|
'redirect_uri' => $this->redirect_uri,
|
||||||
|
'response_type' => $this->response_type,
|
||||||
|
);
|
||||||
|
|
||||||
|
return $params;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function validateAuthorizeRequest(RequestInterface $request, ResponseInterface $response)
|
||||||
|
{
|
||||||
|
// Make sure a valid client id was supplied (we can not redirect because we were unable to verify the URI)
|
||||||
|
if (!$client_id = $request->query('client_id', $request->request('client_id'))) {
|
||||||
|
// We don't have a good URI to use
|
||||||
|
$response->setError(400, 'invalid_client', "No client id supplied");
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get client details
|
||||||
|
if (!$clientData = $this->clientStorage->getClientDetails($client_id)) {
|
||||||
|
$response->setError(400, 'invalid_client', 'The client id supplied is invalid');
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
$registered_redirect_uri = isset($clientData['redirect_uri']) ? $clientData['redirect_uri'] : '';
|
||||||
|
|
||||||
|
// Make sure a valid redirect_uri was supplied. If specified, it must match the clientData URI.
|
||||||
|
// @see http://tools.ietf.org/html/rfc6749#section-3.1.2
|
||||||
|
// @see http://tools.ietf.org/html/rfc6749#section-4.1.2.1
|
||||||
|
// @see http://tools.ietf.org/html/rfc6749#section-4.2.2.1
|
||||||
|
if ($supplied_redirect_uri = $request->query('redirect_uri', $request->request('redirect_uri'))) {
|
||||||
|
// validate there is no fragment supplied
|
||||||
|
$parts = parse_url($supplied_redirect_uri);
|
||||||
|
if (isset($parts['fragment']) && $parts['fragment']) {
|
||||||
|
$response->setError(400, 'invalid_uri', 'The redirect URI must not contain a fragment');
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// validate against the registered redirect uri(s) if available
|
||||||
|
if ($registered_redirect_uri && !$this->validateRedirectUri($supplied_redirect_uri, $registered_redirect_uri)) {
|
||||||
|
$response->setError(400, 'redirect_uri_mismatch', 'The redirect URI provided is missing or does not match', '#section-3.1.2');
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
$redirect_uri = $supplied_redirect_uri;
|
||||||
|
} else {
|
||||||
|
// use the registered redirect_uri if none has been supplied, if possible
|
||||||
|
if (!$registered_redirect_uri) {
|
||||||
|
$response->setError(400, 'invalid_uri', 'No redirect URI was supplied or stored');
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (count(explode(' ', $registered_redirect_uri)) > 1) {
|
||||||
|
$response->setError(400, 'invalid_uri', 'A redirect URI must be supplied when multiple redirect URIs are registered', '#section-3.1.2.3');
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
$redirect_uri = $registered_redirect_uri;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Select the redirect URI
|
||||||
|
$response_type = $request->query('response_type', $request->request('response_type'));
|
||||||
|
|
||||||
|
// for multiple-valued response types - make them alphabetical
|
||||||
|
if (false !== strpos($response_type, ' ')) {
|
||||||
|
$types = explode(' ', $response_type);
|
||||||
|
sort($types);
|
||||||
|
$response_type = ltrim(implode(' ', $types));
|
||||||
|
}
|
||||||
|
|
||||||
|
$state = $request->query('state', $request->request('state'));
|
||||||
|
|
||||||
|
// type and client_id are required
|
||||||
|
if (!$response_type || !in_array($response_type, $this->getValidResponseTypes())) {
|
||||||
|
$response->setRedirect($this->config['redirect_status_code'], $redirect_uri, $state, 'invalid_request', 'Invalid or missing response type', null);
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($response_type == self::RESPONSE_TYPE_AUTHORIZATION_CODE) {
|
||||||
|
if (!isset($this->responseTypes['code'])) {
|
||||||
|
$response->setRedirect($this->config['redirect_status_code'], $redirect_uri, $state, 'unsupported_response_type', 'authorization code grant type not supported', null);
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (!$this->clientStorage->checkRestrictedGrantType($client_id, 'authorization_code')) {
|
||||||
|
$response->setRedirect($this->config['redirect_status_code'], $redirect_uri, $state, 'unauthorized_client', 'The grant type is unauthorized for this client_id', null);
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if ($this->responseTypes['code']->enforceRedirect() && !$redirect_uri) {
|
||||||
|
$response->setError(400, 'redirect_uri_mismatch', 'The redirect URI is mandatory and was not supplied');
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (!$this->config['allow_implicit']) {
|
||||||
|
$response->setRedirect($this->config['redirect_status_code'], $redirect_uri, $state, 'unsupported_response_type', 'implicit grant type not supported', null);
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (!$this->clientStorage->checkRestrictedGrantType($client_id, 'implicit')) {
|
||||||
|
$response->setRedirect($this->config['redirect_status_code'], $redirect_uri, $state, 'unauthorized_client', 'The grant type is unauthorized for this client_id', null);
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// validate requested scope if it exists
|
||||||
|
$requestedScope = $this->scopeUtil->getScopeFromRequest($request);
|
||||||
|
|
||||||
|
if ($requestedScope) {
|
||||||
|
// restrict scope by client specific scope if applicable,
|
||||||
|
// otherwise verify the scope exists
|
||||||
|
$clientScope = $this->clientStorage->getClientScope($client_id);
|
||||||
|
if ((is_null($clientScope) && !$this->scopeUtil->scopeExists($requestedScope))
|
||||||
|
|| ($clientScope && !$this->scopeUtil->checkScope($requestedScope, $clientScope))) {
|
||||||
|
$response->setRedirect($this->config['redirect_status_code'], $redirect_uri, $state, 'invalid_scope', 'An unsupported scope was requested', null);
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// use a globally-defined default scope
|
||||||
|
$defaultScope = $this->scopeUtil->getDefaultScope($client_id);
|
||||||
|
|
||||||
|
if (false === $defaultScope) {
|
||||||
|
$response->setRedirect($this->config['redirect_status_code'], $redirect_uri, $state, 'invalid_client', 'This application requires you specify a scope parameter', null);
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
$requestedScope = $defaultScope;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Validate state parameter exists (if configured to enforce this)
|
||||||
|
if ($this->config['enforce_state'] && !$state) {
|
||||||
|
$response->setRedirect($this->config['redirect_status_code'], $redirect_uri, null, 'invalid_request', 'The state parameter is required');
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// save the input data and return true
|
||||||
|
$this->scope = $requestedScope;
|
||||||
|
$this->state = $state;
|
||||||
|
$this->client_id = $client_id;
|
||||||
|
// Only save the SUPPLIED redirect URI (@see http://tools.ietf.org/html/rfc6749#section-4.1.3)
|
||||||
|
$this->redirect_uri = $supplied_redirect_uri;
|
||||||
|
$this->response_type = $response_type;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Build the absolute URI based on supplied URI and parameters.
|
||||||
|
*
|
||||||
|
* @param $uri An absolute URI.
|
||||||
|
* @param $params Parameters to be append as GET.
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
* An absolute URI with supplied parameters.
|
||||||
|
*
|
||||||
|
* @ingroup oauth2_section_4
|
||||||
|
*/
|
||||||
|
private function buildUri($uri, $params)
|
||||||
|
{
|
||||||
|
$parse_url = parse_url($uri);
|
||||||
|
|
||||||
|
// Add our params to the parsed uri
|
||||||
|
foreach ($params as $k => $v) {
|
||||||
|
if (isset($parse_url[$k])) {
|
||||||
|
$parse_url[$k] .= "&" . http_build_query($v, '', '&');
|
||||||
|
} else {
|
||||||
|
$parse_url[$k] = http_build_query($v, '', '&');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Put humpty dumpty back together
|
||||||
|
return
|
||||||
|
((isset($parse_url["scheme"])) ? $parse_url["scheme"] . "://" : "")
|
||||||
|
. ((isset($parse_url["user"])) ? $parse_url["user"]
|
||||||
|
. ((isset($parse_url["pass"])) ? ":" . $parse_url["pass"] : "") . "@" : "")
|
||||||
|
. ((isset($parse_url["host"])) ? $parse_url["host"] : "")
|
||||||
|
. ((isset($parse_url["port"])) ? ":" . $parse_url["port"] : "")
|
||||||
|
. ((isset($parse_url["path"])) ? $parse_url["path"] : "")
|
||||||
|
. ((isset($parse_url["query"]) && !empty($parse_url['query'])) ? "?" . $parse_url["query"] : "")
|
||||||
|
. ((isset($parse_url["fragment"])) ? "#" . $parse_url["fragment"] : "")
|
||||||
|
;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function getValidResponseTypes()
|
||||||
|
{
|
||||||
|
return array(
|
||||||
|
self::RESPONSE_TYPE_ACCESS_TOKEN,
|
||||||
|
self::RESPONSE_TYPE_AUTHORIZATION_CODE,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Internal method for validating redirect URI supplied
|
||||||
|
*
|
||||||
|
* @param string $inputUri The submitted URI to be validated
|
||||||
|
* @param string $registeredUriString The allowed URI(s) to validate against. Can be a space-delimited string of URIs to
|
||||||
|
* allow for multiple URIs
|
||||||
|
*
|
||||||
|
* @see http://tools.ietf.org/html/rfc6749#section-3.1.2
|
||||||
|
*/
|
||||||
|
protected function validateRedirectUri($inputUri, $registeredUriString)
|
||||||
|
{
|
||||||
|
if (!$inputUri || !$registeredUriString) {
|
||||||
|
return false; // if either one is missing, assume INVALID
|
||||||
|
}
|
||||||
|
|
||||||
|
$registered_uris = preg_split('/\s+/', $registeredUriString);
|
||||||
|
foreach ($registered_uris as $registered_uri) {
|
||||||
|
if ($this->config['require_exact_redirect_uri']) {
|
||||||
|
// the input uri is validated against the registered uri using exact match
|
||||||
|
if (strcmp($inputUri, $registered_uri) === 0) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// the input uri is validated against the registered uri using case-insensitive match of the initial string
|
||||||
|
// i.e. additional query parameters may be applied
|
||||||
|
if (strcasecmp(substr($inputUri, 0, strlen($registered_uri)), $registered_uri) === 0) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Convenience methods to access the parameters derived from the validated request
|
||||||
|
*/
|
||||||
|
|
||||||
|
public function getScope()
|
||||||
|
{
|
||||||
|
return $this->scope;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getState()
|
||||||
|
{
|
||||||
|
return $this->state;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getClientId()
|
||||||
|
{
|
||||||
|
return $this->client_id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getRedirectUri()
|
||||||
|
{
|
||||||
|
return $this->redirect_uri;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getResponseType()
|
||||||
|
{
|
||||||
|
return $this->response_type;
|
||||||
|
}
|
||||||
|
}
|
43
vendor/bshaffer/oauth2-server-php/src/OAuth2/Controller/AuthorizeControllerInterface.php
vendored
Normal file
43
vendor/bshaffer/oauth2-server-php/src/OAuth2/Controller/AuthorizeControllerInterface.php
vendored
Normal file
|
@ -0,0 +1,43 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace OAuth2\Controller;
|
||||||
|
|
||||||
|
use OAuth2\RequestInterface;
|
||||||
|
use OAuth2\ResponseInterface;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This controller is called when a user should be authorized
|
||||||
|
* by an authorization server. As OAuth2 does not handle
|
||||||
|
* authorization directly, this controller ensures the request is valid, but
|
||||||
|
* requires the application to determine the value of $is_authorized
|
||||||
|
*
|
||||||
|
* ex:
|
||||||
|
* > $user_id = $this->somehowDetermineUserId();
|
||||||
|
* > $is_authorized = $this->somehowDetermineUserAuthorization();
|
||||||
|
* > $response = new OAuth2\Response();
|
||||||
|
* > $authorizeController->handleAuthorizeRequest(
|
||||||
|
* > OAuth2\Request::createFromGlobals(),
|
||||||
|
* > $response,
|
||||||
|
* > $is_authorized,
|
||||||
|
* > $user_id);
|
||||||
|
* > $response->send();
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
interface AuthorizeControllerInterface
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* List of possible authentication response types.
|
||||||
|
* The "authorization_code" mechanism exclusively supports 'code'
|
||||||
|
* and the "implicit" mechanism exclusively supports 'token'.
|
||||||
|
*
|
||||||
|
* @var string
|
||||||
|
* @see http://tools.ietf.org/html/rfc6749#section-4.1.1
|
||||||
|
* @see http://tools.ietf.org/html/rfc6749#section-4.2.1
|
||||||
|
*/
|
||||||
|
const RESPONSE_TYPE_AUTHORIZATION_CODE = 'code';
|
||||||
|
const RESPONSE_TYPE_ACCESS_TOKEN = 'token';
|
||||||
|
|
||||||
|
public function handleAuthorizeRequest(RequestInterface $request, ResponseInterface $response, $is_authorized, $user_id = null);
|
||||||
|
|
||||||
|
public function validateAuthorizeRequest(RequestInterface $request, ResponseInterface $response);
|
||||||
|
}
|
111
vendor/bshaffer/oauth2-server-php/src/OAuth2/Controller/ResourceController.php
vendored
Normal file
111
vendor/bshaffer/oauth2-server-php/src/OAuth2/Controller/ResourceController.php
vendored
Normal file
|
@ -0,0 +1,111 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace OAuth2\Controller;
|
||||||
|
|
||||||
|
use OAuth2\TokenType\TokenTypeInterface;
|
||||||
|
use OAuth2\Storage\AccessTokenInterface;
|
||||||
|
use OAuth2\ScopeInterface;
|
||||||
|
use OAuth2\RequestInterface;
|
||||||
|
use OAuth2\ResponseInterface;
|
||||||
|
use OAuth2\Scope;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @see OAuth2\Controller\ResourceControllerInterface
|
||||||
|
*/
|
||||||
|
class ResourceController implements ResourceControllerInterface
|
||||||
|
{
|
||||||
|
private $token;
|
||||||
|
|
||||||
|
protected $tokenType;
|
||||||
|
protected $tokenStorage;
|
||||||
|
protected $config;
|
||||||
|
protected $scopeUtil;
|
||||||
|
|
||||||
|
public function __construct(TokenTypeInterface $tokenType, AccessTokenInterface $tokenStorage, $config = array(), ScopeInterface $scopeUtil = null)
|
||||||
|
{
|
||||||
|
$this->tokenType = $tokenType;
|
||||||
|
$this->tokenStorage = $tokenStorage;
|
||||||
|
|
||||||
|
$this->config = array_merge(array(
|
||||||
|
'www_realm' => 'Service',
|
||||||
|
), $config);
|
||||||
|
|
||||||
|
if (is_null($scopeUtil)) {
|
||||||
|
$scopeUtil = new Scope();
|
||||||
|
}
|
||||||
|
$this->scopeUtil = $scopeUtil;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function verifyResourceRequest(RequestInterface $request, ResponseInterface $response, $scope = null)
|
||||||
|
{
|
||||||
|
$token = $this->getAccessTokenData($request, $response);
|
||||||
|
|
||||||
|
// Check if we have token data
|
||||||
|
if (is_null($token)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check scope, if provided
|
||||||
|
* If token doesn't have a scope, it's null/empty, or it's insufficient, then throw 403
|
||||||
|
* @see http://tools.ietf.org/html/rfc6750#section-3.1
|
||||||
|
*/
|
||||||
|
if ($scope && (!isset($token["scope"]) || !$token["scope"] || !$this->scopeUtil->checkScope($scope, $token["scope"]))) {
|
||||||
|
$response->setError(403, 'insufficient_scope', 'The request requires higher privileges than provided by the access token');
|
||||||
|
$response->addHttpHeaders(array(
|
||||||
|
'WWW-Authenticate' => sprintf('%s realm="%s", scope="%s", error="%s", error_description="%s"',
|
||||||
|
$this->tokenType->getTokenType(),
|
||||||
|
$this->config['www_realm'],
|
||||||
|
$scope,
|
||||||
|
$response->getParameter('error'),
|
||||||
|
$response->getParameter('error_description')
|
||||||
|
)
|
||||||
|
));
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// allow retrieval of the token
|
||||||
|
$this->token = $token;
|
||||||
|
|
||||||
|
return (bool) $token;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getAccessTokenData(RequestInterface $request, ResponseInterface $response)
|
||||||
|
{
|
||||||
|
// Get the token parameter
|
||||||
|
if ($token_param = $this->tokenType->getAccessTokenParameter($request, $response)) {
|
||||||
|
// Get the stored token data (from the implementing subclass)
|
||||||
|
// Check we have a well formed token
|
||||||
|
// Check token expiration (expires is a mandatory paramter)
|
||||||
|
if (!$token = $this->tokenStorage->getAccessToken($token_param)) {
|
||||||
|
$response->setError(401, 'invalid_token', 'The access token provided is invalid');
|
||||||
|
} elseif (!isset($token["expires"]) || !isset($token["client_id"])) {
|
||||||
|
$response->setError(401, 'malformed_token', 'Malformed token (missing "expires")');
|
||||||
|
} elseif (time() > $token["expires"]) {
|
||||||
|
$response->setError(401, 'expired_token', 'The access token provided has expired');
|
||||||
|
} else {
|
||||||
|
return $token;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$authHeader = sprintf('%s realm="%s"', $this->tokenType->getTokenType(), $this->config['www_realm']);
|
||||||
|
|
||||||
|
if ($error = $response->getParameter('error')) {
|
||||||
|
$authHeader = sprintf('%s, error="%s"', $authHeader, $error);
|
||||||
|
if ($error_description = $response->getParameter('error_description')) {
|
||||||
|
$authHeader = sprintf('%s, error_description="%s"', $authHeader, $error_description);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$response->addHttpHeaders(array('WWW-Authenticate' => $authHeader));
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
// convenience method to allow retrieval of the token
|
||||||
|
public function getToken()
|
||||||
|
{
|
||||||
|
return $this->token;
|
||||||
|
}
|
||||||
|
}
|
26
vendor/bshaffer/oauth2-server-php/src/OAuth2/Controller/ResourceControllerInterface.php
vendored
Normal file
26
vendor/bshaffer/oauth2-server-php/src/OAuth2/Controller/ResourceControllerInterface.php
vendored
Normal file
|
@ -0,0 +1,26 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace OAuth2\Controller;
|
||||||
|
|
||||||
|
use OAuth2\RequestInterface;
|
||||||
|
use OAuth2\ResponseInterface;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This controller is called when a "resource" is requested.
|
||||||
|
* call verifyResourceRequest in order to determine if the request
|
||||||
|
* contains a valid token.
|
||||||
|
*
|
||||||
|
* ex:
|
||||||
|
* > if (!$resourceController->verifyResourceRequest(OAuth2\Request::createFromGlobals(), $response = new OAuth2\Response())) {
|
||||||
|
* > $response->send(); // authorization failed
|
||||||
|
* > die();
|
||||||
|
* > }
|
||||||
|
* > return json_encode($resource); // valid token! Send the stuff!
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
interface ResourceControllerInterface
|
||||||
|
{
|
||||||
|
public function verifyResourceRequest(RequestInterface $request, ResponseInterface $response, $scope = null);
|
||||||
|
|
||||||
|
public function getAccessTokenData(RequestInterface $request, ResponseInterface $response);
|
||||||
|
}
|
274
vendor/bshaffer/oauth2-server-php/src/OAuth2/Controller/TokenController.php
vendored
Normal file
274
vendor/bshaffer/oauth2-server-php/src/OAuth2/Controller/TokenController.php
vendored
Normal file
|
@ -0,0 +1,274 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace OAuth2\Controller;
|
||||||
|
|
||||||
|
use OAuth2\ResponseType\AccessTokenInterface;
|
||||||
|
use OAuth2\ClientAssertionType\ClientAssertionTypeInterface;
|
||||||
|
use OAuth2\GrantType\GrantTypeInterface;
|
||||||
|
use OAuth2\ScopeInterface;
|
||||||
|
use OAuth2\Scope;
|
||||||
|
use OAuth2\Storage\ClientInterface;
|
||||||
|
use OAuth2\RequestInterface;
|
||||||
|
use OAuth2\ResponseInterface;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @see OAuth2\Controller\TokenControllerInterface
|
||||||
|
*/
|
||||||
|
class TokenController implements TokenControllerInterface
|
||||||
|
{
|
||||||
|
protected $accessToken;
|
||||||
|
protected $grantTypes;
|
||||||
|
protected $clientAssertionType;
|
||||||
|
protected $scopeUtil;
|
||||||
|
protected $clientStorage;
|
||||||
|
|
||||||
|
public function __construct(AccessTokenInterface $accessToken, ClientInterface $clientStorage, array $grantTypes = array(), ClientAssertionTypeInterface $clientAssertionType = null, ScopeInterface $scopeUtil = null)
|
||||||
|
{
|
||||||
|
if (is_null($clientAssertionType)) {
|
||||||
|
foreach ($grantTypes as $grantType) {
|
||||||
|
if (!$grantType instanceof ClientAssertionTypeInterface) {
|
||||||
|
throw new \InvalidArgumentException('You must supply an instance of OAuth2\ClientAssertionType\ClientAssertionTypeInterface or only use grant types which implement OAuth2\ClientAssertionType\ClientAssertionTypeInterface');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
$this->clientAssertionType = $clientAssertionType;
|
||||||
|
$this->accessToken = $accessToken;
|
||||||
|
$this->clientStorage = $clientStorage;
|
||||||
|
foreach ($grantTypes as $grantType) {
|
||||||
|
$this->addGrantType($grantType);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (is_null($scopeUtil)) {
|
||||||
|
$scopeUtil = new Scope();
|
||||||
|
}
|
||||||
|
$this->scopeUtil = $scopeUtil;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function handleTokenRequest(RequestInterface $request, ResponseInterface $response)
|
||||||
|
{
|
||||||
|
if ($token = $this->grantAccessToken($request, $response)) {
|
||||||
|
// @see http://tools.ietf.org/html/rfc6749#section-5.1
|
||||||
|
// server MUST disable caching in headers when tokens are involved
|
||||||
|
$response->setStatusCode(200);
|
||||||
|
$response->addParameters($token);
|
||||||
|
$response->addHttpHeaders(array('Cache-Control' => 'no-store', 'Pragma' => 'no-cache'));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Grant or deny a requested access token.
|
||||||
|
* This would be called from the "/token" endpoint as defined in the spec.
|
||||||
|
* You can call your endpoint whatever you want.
|
||||||
|
*
|
||||||
|
* @param $request - RequestInterface
|
||||||
|
* Request object to grant access token
|
||||||
|
*
|
||||||
|
* @throws InvalidArgumentException
|
||||||
|
* @throws LogicException
|
||||||
|
*
|
||||||
|
* @see http://tools.ietf.org/html/rfc6749#section-4
|
||||||
|
* @see http://tools.ietf.org/html/rfc6749#section-10.6
|
||||||
|
* @see http://tools.ietf.org/html/rfc6749#section-4.1.3
|
||||||
|
*
|
||||||
|
* @ingroup oauth2_section_4
|
||||||
|
*/
|
||||||
|
public function grantAccessToken(RequestInterface $request, ResponseInterface $response)
|
||||||
|
{
|
||||||
|
if (strtolower($request->server('REQUEST_METHOD')) != 'post') {
|
||||||
|
$response->setError(405, 'invalid_request', 'The request method must be POST when requesting an access token', '#section-3.2');
|
||||||
|
$response->addHttpHeaders(array('Allow' => 'POST'));
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Determine grant type from request
|
||||||
|
* and validate the request for that grant type
|
||||||
|
*/
|
||||||
|
if (!$grantTypeIdentifier = $request->request('grant_type')) {
|
||||||
|
$response->setError(400, 'invalid_request', 'The grant type was not specified in the request');
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!isset($this->grantTypes[$grantTypeIdentifier])) {
|
||||||
|
/* TODO: If this is an OAuth2 supported grant type that we have chosen not to implement, throw a 501 Not Implemented instead */
|
||||||
|
$response->setError(400, 'unsupported_grant_type', sprintf('Grant type "%s" not supported', $grantTypeIdentifier));
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
$grantType = $this->grantTypes[$grantTypeIdentifier];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieve the client information from the request
|
||||||
|
* ClientAssertionTypes allow for grant types which also assert the client data
|
||||||
|
* in which case ClientAssertion is handled in the validateRequest method
|
||||||
|
*
|
||||||
|
* @see OAuth2\GrantType\JWTBearer
|
||||||
|
* @see OAuth2\GrantType\ClientCredentials
|
||||||
|
*/
|
||||||
|
if (!$grantType instanceof ClientAssertionTypeInterface) {
|
||||||
|
if (!$this->clientAssertionType->validateRequest($request, $response)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
$clientId = $this->clientAssertionType->getClientId();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieve the grant type information from the request
|
||||||
|
* The GrantTypeInterface object handles all validation
|
||||||
|
* If the object is an instance of ClientAssertionTypeInterface,
|
||||||
|
* That logic is handled here as well
|
||||||
|
*/
|
||||||
|
if (!$grantType->validateRequest($request, $response)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($grantType instanceof ClientAssertionTypeInterface) {
|
||||||
|
$clientId = $grantType->getClientId();
|
||||||
|
} else {
|
||||||
|
// validate the Client ID (if applicable)
|
||||||
|
if (!is_null($storedClientId = $grantType->getClientId()) && $storedClientId != $clientId) {
|
||||||
|
$response->setError(400, 'invalid_grant', sprintf('%s doesn\'t exist or is invalid for the client', $grantTypeIdentifier));
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Validate the client can use the requested grant type
|
||||||
|
*/
|
||||||
|
if (!$this->clientStorage->checkRestrictedGrantType($clientId, $grantTypeIdentifier)) {
|
||||||
|
$response->setError(400, 'unauthorized_client', 'The grant type is unauthorized for this client_id');
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Validate the scope of the token
|
||||||
|
*
|
||||||
|
* requestedScope - the scope specified in the token request
|
||||||
|
* availableScope - the scope associated with the grant type
|
||||||
|
* ex: in the case of the "Authorization Code" grant type,
|
||||||
|
* the scope is specified in the authorize request
|
||||||
|
*
|
||||||
|
* @see http://tools.ietf.org/html/rfc6749#section-3.3
|
||||||
|
*/
|
||||||
|
|
||||||
|
$requestedScope = $this->scopeUtil->getScopeFromRequest($request);
|
||||||
|
$availableScope = $grantType->getScope();
|
||||||
|
|
||||||
|
if ($requestedScope) {
|
||||||
|
// validate the requested scope
|
||||||
|
if ($availableScope) {
|
||||||
|
if (!$this->scopeUtil->checkScope($requestedScope, $availableScope)) {
|
||||||
|
$response->setError(400, 'invalid_scope', 'The scope requested is invalid for this request');
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// validate the client has access to this scope
|
||||||
|
if ($clientScope = $this->clientStorage->getClientScope($clientId)) {
|
||||||
|
if (!$this->scopeUtil->checkScope($requestedScope, $clientScope)) {
|
||||||
|
$response->setError(400, 'invalid_scope', 'The scope requested is invalid for this client');
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
} elseif (!$this->scopeUtil->scopeExists($requestedScope)) {
|
||||||
|
$response->setError(400, 'invalid_scope', 'An unsupported scope was requested');
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} elseif ($availableScope) {
|
||||||
|
// use the scope associated with this grant type
|
||||||
|
$requestedScope = $availableScope;
|
||||||
|
} else {
|
||||||
|
// use a globally-defined default scope
|
||||||
|
$defaultScope = $this->scopeUtil->getDefaultScope($clientId);
|
||||||
|
|
||||||
|
// "false" means default scopes are not allowed
|
||||||
|
if (false === $defaultScope) {
|
||||||
|
$response->setError(400, 'invalid_scope', 'This application requires you specify a scope parameter');
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
$requestedScope = $defaultScope;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $grantType->createAccessToken($this->accessToken, $clientId, $grantType->getUserId(), $requestedScope);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* addGrantType
|
||||||
|
*
|
||||||
|
* @param grantType - OAuth2\GrantTypeInterface
|
||||||
|
* the grant type to add for the specified identifier
|
||||||
|
* @param identifier - string
|
||||||
|
* a string passed in as "grant_type" in the response that will call this grantType
|
||||||
|
*/
|
||||||
|
public function addGrantType(GrantTypeInterface $grantType, $identifier = null)
|
||||||
|
{
|
||||||
|
if (is_null($identifier) || is_numeric($identifier)) {
|
||||||
|
$identifier = $grantType->getQuerystringIdentifier();
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->grantTypes[$identifier] = $grantType;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function handleRevokeRequest(RequestInterface $request, ResponseInterface $response)
|
||||||
|
{
|
||||||
|
if ($this->revokeToken($request, $response)) {
|
||||||
|
$response->setStatusCode(200);
|
||||||
|
$response->addParameters(array('revoked' => true));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Revoke a refresh or access token. Returns true on success and when tokens are invalid
|
||||||
|
*
|
||||||
|
* Note: invalid tokens do not cause an error response since the client
|
||||||
|
* cannot handle such an error in a reasonable way. Moreover, the
|
||||||
|
* purpose of the revocation request, invalidating the particular token,
|
||||||
|
* is already achieved.
|
||||||
|
*
|
||||||
|
* @param RequestInterface $request
|
||||||
|
* @param ResponseInterface $response
|
||||||
|
* @return bool|null
|
||||||
|
*/
|
||||||
|
public function revokeToken(RequestInterface $request, ResponseInterface $response)
|
||||||
|
{
|
||||||
|
if (strtolower($request->server('REQUEST_METHOD')) != 'post') {
|
||||||
|
$response->setError(405, 'invalid_request', 'The request method must be POST when revoking an access token', '#section-3.2');
|
||||||
|
$response->addHttpHeaders(array('Allow' => 'POST'));
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
$token_type_hint = $request->request('token_type_hint');
|
||||||
|
if (!in_array($token_type_hint, array(null, 'access_token', 'refresh_token'), true)) {
|
||||||
|
$response->setError(400, 'invalid_request', 'Token type hint must be either \'access_token\' or \'refresh_token\'');
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
$token = $request->request('token');
|
||||||
|
if ($token === null) {
|
||||||
|
$response->setError(400, 'invalid_request', 'Missing token parameter to revoke');
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
// @todo remove this check for v2.0
|
||||||
|
if (!method_exists($this->accessToken, 'revokeToken')) {
|
||||||
|
$class = get_class($this->accessToken);
|
||||||
|
throw new \RuntimeException("AccessToken {$class} does not implement required revokeToken method");
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->accessToken->revokeToken($token, $token_type_hint);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
32
vendor/bshaffer/oauth2-server-php/src/OAuth2/Controller/TokenControllerInterface.php
vendored
Normal file
32
vendor/bshaffer/oauth2-server-php/src/OAuth2/Controller/TokenControllerInterface.php
vendored
Normal file
|
@ -0,0 +1,32 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace OAuth2\Controller;
|
||||||
|
|
||||||
|
use OAuth2\RequestInterface;
|
||||||
|
use OAuth2\ResponseInterface;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This controller is called when a token is being requested.
|
||||||
|
* it is called to handle all grant types the application supports.
|
||||||
|
* It also validates the client's credentials
|
||||||
|
*
|
||||||
|
* ex:
|
||||||
|
* > $tokenController->handleTokenRequest(OAuth2\Request::createFromGlobals(), $response = new OAuth2\Response());
|
||||||
|
* > $response->send();
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
interface TokenControllerInterface
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* handleTokenRequest
|
||||||
|
*
|
||||||
|
* @param $request
|
||||||
|
* OAuth2\RequestInterface - The current http request
|
||||||
|
* @param $response
|
||||||
|
* OAuth2\ResponseInterface - An instance of OAuth2\ResponseInterface to contain the response data
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public function handleTokenRequest(RequestInterface $request, ResponseInterface $response);
|
||||||
|
|
||||||
|
public function grantAccessToken(RequestInterface $request, ResponseInterface $response);
|
||||||
|
}
|
11
vendor/bshaffer/oauth2-server-php/src/OAuth2/Encryption/EncryptionInterface.php
vendored
Normal file
11
vendor/bshaffer/oauth2-server-php/src/OAuth2/Encryption/EncryptionInterface.php
vendored
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace OAuth2\Encryption;
|
||||||
|
|
||||||
|
interface EncryptionInterface
|
||||||
|
{
|
||||||
|
public function encode($payload, $key, $algorithm = null);
|
||||||
|
public function decode($payload, $key, $algorithm = null);
|
||||||
|
public function urlSafeB64Encode($data);
|
||||||
|
public function urlSafeB64Decode($b64);
|
||||||
|
}
|
47
vendor/bshaffer/oauth2-server-php/src/OAuth2/Encryption/FirebaseJwt.php
vendored
Normal file
47
vendor/bshaffer/oauth2-server-php/src/OAuth2/Encryption/FirebaseJwt.php
vendored
Normal file
|
@ -0,0 +1,47 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace OAuth2\Encryption;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Bridge file to use the firebase/php-jwt package for JWT encoding and decoding.
|
||||||
|
* @author Francis Chuang <francis.chuang@gmail.com>
|
||||||
|
*/
|
||||||
|
class FirebaseJwt implements EncryptionInterface
|
||||||
|
{
|
||||||
|
public function __construct()
|
||||||
|
{
|
||||||
|
if (!class_exists('\JWT')) {
|
||||||
|
throw new \ErrorException('firebase/php-jwt must be installed to use this feature. You can do this by running "composer require firebase/php-jwt"');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public function encode($payload, $key, $alg = 'HS256', $keyId = null)
|
||||||
|
{
|
||||||
|
return \JWT::encode($payload, $key, $alg, $keyId);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function decode($jwt, $key = null, $allowedAlgorithms = null)
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
|
||||||
|
//Maintain BC: Do not verify if no algorithms are passed in.
|
||||||
|
if (!$allowedAlgorithms) {
|
||||||
|
$key = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (array)\JWT::decode($jwt, $key, $allowedAlgorithms);
|
||||||
|
} catch (\Exception $e) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public function urlSafeB64Encode($data)
|
||||||
|
{
|
||||||
|
return \JWT::urlsafeB64Encode($data);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function urlSafeB64Decode($b64)
|
||||||
|
{
|
||||||
|
return \JWT::urlsafeB64Decode($b64);
|
||||||
|
}
|
||||||
|
}
|
173
vendor/bshaffer/oauth2-server-php/src/OAuth2/Encryption/Jwt.php
vendored
Normal file
173
vendor/bshaffer/oauth2-server-php/src/OAuth2/Encryption/Jwt.php
vendored
Normal file
|
@ -0,0 +1,173 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace OAuth2\Encryption;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @link https://github.com/F21/jwt
|
||||||
|
* @author F21
|
||||||
|
*/
|
||||||
|
class Jwt implements EncryptionInterface
|
||||||
|
{
|
||||||
|
public function encode($payload, $key, $algo = 'HS256')
|
||||||
|
{
|
||||||
|
$header = $this->generateJwtHeader($payload, $algo);
|
||||||
|
|
||||||
|
$segments = array(
|
||||||
|
$this->urlSafeB64Encode(json_encode($header)),
|
||||||
|
$this->urlSafeB64Encode(json_encode($payload))
|
||||||
|
);
|
||||||
|
|
||||||
|
$signing_input = implode('.', $segments);
|
||||||
|
|
||||||
|
$signature = $this->sign($signing_input, $key, $algo);
|
||||||
|
$segments[] = $this->urlsafeB64Encode($signature);
|
||||||
|
|
||||||
|
return implode('.', $segments);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function decode($jwt, $key = null, $allowedAlgorithms = true)
|
||||||
|
{
|
||||||
|
if (!strpos($jwt, '.')) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
$tks = explode('.', $jwt);
|
||||||
|
|
||||||
|
if (count($tks) != 3) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
list($headb64, $payloadb64, $cryptob64) = $tks;
|
||||||
|
|
||||||
|
if (null === ($header = json_decode($this->urlSafeB64Decode($headb64), true))) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (null === $payload = json_decode($this->urlSafeB64Decode($payloadb64), true)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
$sig = $this->urlSafeB64Decode($cryptob64);
|
||||||
|
|
||||||
|
if ((bool) $allowedAlgorithms) {
|
||||||
|
if (!isset($header['alg'])) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// check if bool arg supplied here to maintain BC
|
||||||
|
if (is_array($allowedAlgorithms) && !in_array($header['alg'], $allowedAlgorithms)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!$this->verifySignature($sig, "$headb64.$payloadb64", $key, $header['alg'])) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $payload;
|
||||||
|
}
|
||||||
|
|
||||||
|
private function verifySignature($signature, $input, $key, $algo = 'HS256')
|
||||||
|
{
|
||||||
|
// use constants when possible, for HipHop support
|
||||||
|
switch ($algo) {
|
||||||
|
case'HS256':
|
||||||
|
case'HS384':
|
||||||
|
case'HS512':
|
||||||
|
return $this->hash_equals(
|
||||||
|
$this->sign($input, $key, $algo),
|
||||||
|
$signature
|
||||||
|
);
|
||||||
|
|
||||||
|
case 'RS256':
|
||||||
|
return openssl_verify($input, $signature, $key, defined('OPENSSL_ALGO_SHA256') ? OPENSSL_ALGO_SHA256 : 'sha256') === 1;
|
||||||
|
|
||||||
|
case 'RS384':
|
||||||
|
return @openssl_verify($input, $signature, $key, defined('OPENSSL_ALGO_SHA384') ? OPENSSL_ALGO_SHA384 : 'sha384') === 1;
|
||||||
|
|
||||||
|
case 'RS512':
|
||||||
|
return @openssl_verify($input, $signature, $key, defined('OPENSSL_ALGO_SHA512') ? OPENSSL_ALGO_SHA512 : 'sha512') === 1;
|
||||||
|
|
||||||
|
default:
|
||||||
|
throw new \InvalidArgumentException("Unsupported or invalid signing algorithm.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private function sign($input, $key, $algo = 'HS256')
|
||||||
|
{
|
||||||
|
switch ($algo) {
|
||||||
|
case 'HS256':
|
||||||
|
return hash_hmac('sha256', $input, $key, true);
|
||||||
|
|
||||||
|
case 'HS384':
|
||||||
|
return hash_hmac('sha384', $input, $key, true);
|
||||||
|
|
||||||
|
case 'HS512':
|
||||||
|
return hash_hmac('sha512', $input, $key, true);
|
||||||
|
|
||||||
|
case 'RS256':
|
||||||
|
return $this->generateRSASignature($input, $key, defined('OPENSSL_ALGO_SHA256') ? OPENSSL_ALGO_SHA256 : 'sha256');
|
||||||
|
|
||||||
|
case 'RS384':
|
||||||
|
return $this->generateRSASignature($input, $key, defined('OPENSSL_ALGO_SHA384') ? OPENSSL_ALGO_SHA384 : 'sha384');
|
||||||
|
|
||||||
|
case 'RS512':
|
||||||
|
return $this->generateRSASignature($input, $key, defined('OPENSSL_ALGO_SHA512') ? OPENSSL_ALGO_SHA512 : 'sha512');
|
||||||
|
|
||||||
|
default:
|
||||||
|
throw new \Exception("Unsupported or invalid signing algorithm.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private function generateRSASignature($input, $key, $algo)
|
||||||
|
{
|
||||||
|
if (!openssl_sign($input, $signature, $key, $algo)) {
|
||||||
|
throw new \Exception("Unable to sign data.");
|
||||||
|
}
|
||||||
|
|
||||||
|
return $signature;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function urlSafeB64Encode($data)
|
||||||
|
{
|
||||||
|
$b64 = base64_encode($data);
|
||||||
|
$b64 = str_replace(array('+', '/', "\r", "\n", '='),
|
||||||
|
array('-', '_'),
|
||||||
|
$b64);
|
||||||
|
|
||||||
|
return $b64;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function urlSafeB64Decode($b64)
|
||||||
|
{
|
||||||
|
$b64 = str_replace(array('-', '_'),
|
||||||
|
array('+', '/'),
|
||||||
|
$b64);
|
||||||
|
|
||||||
|
return base64_decode($b64);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Override to create a custom header
|
||||||
|
*/
|
||||||
|
protected function generateJwtHeader($payload, $algorithm)
|
||||||
|
{
|
||||||
|
return array(
|
||||||
|
'typ' => 'JWT',
|
||||||
|
'alg' => $algorithm,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function hash_equals($a, $b)
|
||||||
|
{
|
||||||
|
if (function_exists('hash_equals')) {
|
||||||
|
return hash_equals($a, $b);
|
||||||
|
}
|
||||||
|
$diff = strlen($a) ^ strlen($b);
|
||||||
|
for ($i = 0; $i < strlen($a) && $i < strlen($b); $i++) {
|
||||||
|
$diff |= ord($a[$i]) ^ ord($b[$i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $diff === 0;
|
||||||
|
}
|
||||||
|
}
|
100
vendor/bshaffer/oauth2-server-php/src/OAuth2/GrantType/AuthorizationCode.php
vendored
Normal file
100
vendor/bshaffer/oauth2-server-php/src/OAuth2/GrantType/AuthorizationCode.php
vendored
Normal file
|
@ -0,0 +1,100 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace OAuth2\GrantType;
|
||||||
|
|
||||||
|
use OAuth2\Storage\AuthorizationCodeInterface;
|
||||||
|
use OAuth2\ResponseType\AccessTokenInterface;
|
||||||
|
use OAuth2\RequestInterface;
|
||||||
|
use OAuth2\ResponseInterface;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @author Brent Shaffer <bshafs at gmail dot com>
|
||||||
|
*/
|
||||||
|
class AuthorizationCode implements GrantTypeInterface
|
||||||
|
{
|
||||||
|
protected $storage;
|
||||||
|
protected $authCode;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param OAuth2\Storage\AuthorizationCodeInterface $storage REQUIRED Storage class for retrieving authorization code information
|
||||||
|
*/
|
||||||
|
public function __construct(AuthorizationCodeInterface $storage)
|
||||||
|
{
|
||||||
|
$this->storage = $storage;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getQuerystringIdentifier()
|
||||||
|
{
|
||||||
|
return 'authorization_code';
|
||||||
|
}
|
||||||
|
|
||||||
|
public function validateRequest(RequestInterface $request, ResponseInterface $response)
|
||||||
|
{
|
||||||
|
if (!$request->request('code')) {
|
||||||
|
$response->setError(400, 'invalid_request', 'Missing parameter: "code" is required');
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
$code = $request->request('code');
|
||||||
|
if (!$authCode = $this->storage->getAuthorizationCode($code)) {
|
||||||
|
$response->setError(400, 'invalid_grant', 'Authorization code doesn\'t exist or is invalid for the client');
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 4.1.3 - ensure that the "redirect_uri" parameter is present if the "redirect_uri" parameter was included in the initial authorization request
|
||||||
|
* @uri - http://tools.ietf.org/html/rfc6749#section-4.1.3
|
||||||
|
*/
|
||||||
|
if (isset($authCode['redirect_uri']) && $authCode['redirect_uri']) {
|
||||||
|
if (!$request->request('redirect_uri') || urldecode($request->request('redirect_uri')) != $authCode['redirect_uri']) {
|
||||||
|
$response->setError(400, 'redirect_uri_mismatch', "The redirect URI is missing or do not match", "#section-4.1.3");
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!isset($authCode['expires'])) {
|
||||||
|
throw new \Exception('Storage must return authcode with a value for "expires"');
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($authCode["expires"] < time()) {
|
||||||
|
$response->setError(400, 'invalid_grant', "The authorization code has expired");
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!isset($authCode['code'])) {
|
||||||
|
$authCode['code'] = $code; // used to expire the code after the access token is granted
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->authCode = $authCode;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getClientId()
|
||||||
|
{
|
||||||
|
return $this->authCode['client_id'];
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getScope()
|
||||||
|
{
|
||||||
|
return isset($this->authCode['scope']) ? $this->authCode['scope'] : null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getUserId()
|
||||||
|
{
|
||||||
|
return isset($this->authCode['user_id']) ? $this->authCode['user_id'] : null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function createAccessToken(AccessTokenInterface $accessToken, $client_id, $user_id, $scope)
|
||||||
|
{
|
||||||
|
$token = $accessToken->createAccessToken($client_id, $user_id, $scope);
|
||||||
|
$this->storage->expireAuthorizationCode($this->authCode['code']);
|
||||||
|
|
||||||
|
return $token;
|
||||||
|
}
|
||||||
|
}
|
67
vendor/bshaffer/oauth2-server-php/src/OAuth2/GrantType/ClientCredentials.php
vendored
Normal file
67
vendor/bshaffer/oauth2-server-php/src/OAuth2/GrantType/ClientCredentials.php
vendored
Normal file
|
@ -0,0 +1,67 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace OAuth2\GrantType;
|
||||||
|
|
||||||
|
use OAuth2\ClientAssertionType\HttpBasic;
|
||||||
|
use OAuth2\ResponseType\AccessTokenInterface;
|
||||||
|
use OAuth2\Storage\ClientCredentialsInterface;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Brent Shaffer <bshafs at gmail dot com>
|
||||||
|
*
|
||||||
|
* @see OAuth2\ClientAssertionType_HttpBasic
|
||||||
|
*/
|
||||||
|
class ClientCredentials extends HttpBasic implements GrantTypeInterface
|
||||||
|
{
|
||||||
|
private $clientData;
|
||||||
|
|
||||||
|
public function __construct(ClientCredentialsInterface $storage, array $config = array())
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* The client credentials grant type MUST only be used by confidential clients
|
||||||
|
*
|
||||||
|
* @see http://tools.ietf.org/html/rfc6749#section-4.4
|
||||||
|
*/
|
||||||
|
$config['allow_public_clients'] = false;
|
||||||
|
|
||||||
|
parent::__construct($storage, $config);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getQuerystringIdentifier()
|
||||||
|
{
|
||||||
|
return 'client_credentials';
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getScope()
|
||||||
|
{
|
||||||
|
$this->loadClientData();
|
||||||
|
|
||||||
|
return isset($this->clientData['scope']) ? $this->clientData['scope'] : null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getUserId()
|
||||||
|
{
|
||||||
|
$this->loadClientData();
|
||||||
|
|
||||||
|
return isset($this->clientData['user_id']) ? $this->clientData['user_id'] : null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function createAccessToken(AccessTokenInterface $accessToken, $client_id, $user_id, $scope)
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Client Credentials Grant does NOT include a refresh token
|
||||||
|
*
|
||||||
|
* @see http://tools.ietf.org/html/rfc6749#section-4.4.3
|
||||||
|
*/
|
||||||
|
$includeRefreshToken = false;
|
||||||
|
|
||||||
|
return $accessToken->createAccessToken($client_id, $user_id, $scope, $includeRefreshToken);
|
||||||
|
}
|
||||||
|
|
||||||
|
private function loadClientData()
|
||||||
|
{
|
||||||
|
if (!$this->clientData) {
|
||||||
|
$this->clientData = $this->storage->getClientDetails($this->getClientId());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
20
vendor/bshaffer/oauth2-server-php/src/OAuth2/GrantType/GrantTypeInterface.php
vendored
Normal file
20
vendor/bshaffer/oauth2-server-php/src/OAuth2/GrantType/GrantTypeInterface.php
vendored
Normal file
|
@ -0,0 +1,20 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace OAuth2\GrantType;
|
||||||
|
|
||||||
|
use OAuth2\ResponseType\AccessTokenInterface;
|
||||||
|
use OAuth2\RequestInterface;
|
||||||
|
use OAuth2\ResponseInterface;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Interface for all OAuth2 Grant Types
|
||||||
|
*/
|
||||||
|
interface GrantTypeInterface
|
||||||
|
{
|
||||||
|
public function getQuerystringIdentifier();
|
||||||
|
public function validateRequest(RequestInterface $request, ResponseInterface $response);
|
||||||
|
public function getClientId();
|
||||||
|
public function getUserId();
|
||||||
|
public function getScope();
|
||||||
|
public function createAccessToken(AccessTokenInterface $accessToken, $client_id, $user_id, $scope);
|
||||||
|
}
|
226
vendor/bshaffer/oauth2-server-php/src/OAuth2/GrantType/JwtBearer.php
vendored
Normal file
226
vendor/bshaffer/oauth2-server-php/src/OAuth2/GrantType/JwtBearer.php
vendored
Normal file
|
@ -0,0 +1,226 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace OAuth2\GrantType;
|
||||||
|
|
||||||
|
use OAuth2\ClientAssertionType\ClientAssertionTypeInterface;
|
||||||
|
use OAuth2\Storage\JwtBearerInterface;
|
||||||
|
use OAuth2\Encryption\Jwt;
|
||||||
|
use OAuth2\Encryption\EncryptionInterface;
|
||||||
|
use OAuth2\ResponseType\AccessTokenInterface;
|
||||||
|
use OAuth2\RequestInterface;
|
||||||
|
use OAuth2\ResponseInterface;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The JWT bearer authorization grant implements JWT (JSON Web Tokens) as a grant type per the IETF draft.
|
||||||
|
*
|
||||||
|
* @see http://tools.ietf.org/html/draft-ietf-oauth-jwt-bearer-04#section-4
|
||||||
|
*
|
||||||
|
* @author F21
|
||||||
|
* @author Brent Shaffer <bshafs at gmail dot com>
|
||||||
|
*/
|
||||||
|
class JwtBearer implements GrantTypeInterface, ClientAssertionTypeInterface
|
||||||
|
{
|
||||||
|
private $jwt;
|
||||||
|
|
||||||
|
protected $storage;
|
||||||
|
protected $audience;
|
||||||
|
protected $jwtUtil;
|
||||||
|
protected $allowedAlgorithms;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates an instance of the JWT bearer grant type.
|
||||||
|
*
|
||||||
|
* @param OAuth2\Storage\JWTBearerInterface|JwtBearerInterface $storage A valid storage interface that implements storage hooks for the JWT bearer grant type.
|
||||||
|
* @param string $audience The audience to validate the token against. This is usually the full URI of the OAuth token requests endpoint.
|
||||||
|
* @param EncryptionInterface|OAuth2\Encryption\JWT $jwtUtil OPTONAL The class used to decode, encode and verify JWTs.
|
||||||
|
* @param array $config
|
||||||
|
*/
|
||||||
|
public function __construct(JwtBearerInterface $storage, $audience, EncryptionInterface $jwtUtil = null, array $config = array())
|
||||||
|
{
|
||||||
|
$this->storage = $storage;
|
||||||
|
$this->audience = $audience;
|
||||||
|
|
||||||
|
if (is_null($jwtUtil)) {
|
||||||
|
$jwtUtil = new Jwt();
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->config = array_merge(array(
|
||||||
|
'allowed_algorithms' => array('RS256', 'RS384', 'RS512')
|
||||||
|
), $config);
|
||||||
|
|
||||||
|
$this->jwtUtil = $jwtUtil;
|
||||||
|
|
||||||
|
$this->allowedAlgorithms = $this->config['allowed_algorithms'];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the grant_type get parameter to identify the grant type request as JWT bearer authorization grant.
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
* The string identifier for grant_type.
|
||||||
|
*
|
||||||
|
* @see OAuth2\GrantType\GrantTypeInterface::getQuerystringIdentifier()
|
||||||
|
*/
|
||||||
|
public function getQuerystringIdentifier()
|
||||||
|
{
|
||||||
|
return 'urn:ietf:params:oauth:grant-type:jwt-bearer';
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Validates the data from the decoded JWT.
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
* TRUE if the JWT request is valid and can be decoded. Otherwise, FALSE is returned.
|
||||||
|
*
|
||||||
|
* @see OAuth2\GrantType\GrantTypeInterface::getTokenData()
|
||||||
|
*/
|
||||||
|
public function validateRequest(RequestInterface $request, ResponseInterface $response)
|
||||||
|
{
|
||||||
|
if (!$request->request("assertion")) {
|
||||||
|
$response->setError(400, 'invalid_request', 'Missing parameters: "assertion" required');
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Store the undecoded JWT for later use
|
||||||
|
$undecodedJWT = $request->request('assertion');
|
||||||
|
|
||||||
|
// Decode the JWT
|
||||||
|
$jwt = $this->jwtUtil->decode($request->request('assertion'), null, false);
|
||||||
|
|
||||||
|
if (!$jwt) {
|
||||||
|
$response->setError(400, 'invalid_request', "JWT is malformed");
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ensure these properties contain a value
|
||||||
|
// @todo: throw malformed error for missing properties
|
||||||
|
$jwt = array_merge(array(
|
||||||
|
'scope' => null,
|
||||||
|
'iss' => null,
|
||||||
|
'sub' => null,
|
||||||
|
'aud' => null,
|
||||||
|
'exp' => null,
|
||||||
|
'nbf' => null,
|
||||||
|
'iat' => null,
|
||||||
|
'jti' => null,
|
||||||
|
'typ' => null,
|
||||||
|
), $jwt);
|
||||||
|
|
||||||
|
if (!isset($jwt['iss'])) {
|
||||||
|
$response->setError(400, 'invalid_grant', "Invalid issuer (iss) provided");
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!isset($jwt['sub'])) {
|
||||||
|
$response->setError(400, 'invalid_grant', "Invalid subject (sub) provided");
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!isset($jwt['exp'])) {
|
||||||
|
$response->setError(400, 'invalid_grant', "Expiration (exp) time must be present");
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check expiration
|
||||||
|
if (ctype_digit($jwt['exp'])) {
|
||||||
|
if ($jwt['exp'] <= time()) {
|
||||||
|
$response->setError(400, 'invalid_grant', "JWT has expired");
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
$response->setError(400, 'invalid_grant', "Expiration (exp) time must be a unix time stamp");
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check the not before time
|
||||||
|
if ($notBefore = $jwt['nbf']) {
|
||||||
|
if (ctype_digit($notBefore)) {
|
||||||
|
if ($notBefore > time()) {
|
||||||
|
$response->setError(400, 'invalid_grant', "JWT cannot be used before the Not Before (nbf) time");
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
$response->setError(400, 'invalid_grant', "Not Before (nbf) time must be a unix time stamp");
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check the audience if required to match
|
||||||
|
if (!isset($jwt['aud']) || ($jwt['aud'] != $this->audience)) {
|
||||||
|
$response->setError(400, 'invalid_grant', "Invalid audience (aud)");
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check the jti (nonce)
|
||||||
|
// @see http://tools.ietf.org/html/draft-ietf-oauth-json-web-token-13#section-4.1.7
|
||||||
|
if (isset($jwt['jti'])) {
|
||||||
|
$jti = $this->storage->getJti($jwt['iss'], $jwt['sub'], $jwt['aud'], $jwt['exp'], $jwt['jti']);
|
||||||
|
|
||||||
|
//Reject if jti is used and jwt is still valid (exp parameter has not expired).
|
||||||
|
if ($jti && $jti['expires'] > time()) {
|
||||||
|
$response->setError(400, 'invalid_grant', "JSON Token Identifier (jti) has already been used");
|
||||||
|
|
||||||
|
return null;
|
||||||
|
} else {
|
||||||
|
$this->storage->setJti($jwt['iss'], $jwt['sub'], $jwt['aud'], $jwt['exp'], $jwt['jti']);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get the iss's public key
|
||||||
|
// @see http://tools.ietf.org/html/draft-ietf-oauth-json-web-token-06#section-4.1.1
|
||||||
|
if (!$key = $this->storage->getClientKey($jwt['iss'], $jwt['sub'])) {
|
||||||
|
$response->setError(400, 'invalid_grant', "Invalid issuer (iss) or subject (sub) provided");
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Verify the JWT
|
||||||
|
if (!$this->jwtUtil->decode($undecodedJWT, $key, $this->allowedAlgorithms)) {
|
||||||
|
$response->setError(400, 'invalid_grant', "JWT failed signature verification");
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->jwt = $jwt;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getClientId()
|
||||||
|
{
|
||||||
|
return $this->jwt['iss'];
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getUserId()
|
||||||
|
{
|
||||||
|
return $this->jwt['sub'];
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getScope()
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates an access token that is NOT associated with a refresh token.
|
||||||
|
* If a subject (sub) the name of the user/account we are accessing data on behalf of.
|
||||||
|
*
|
||||||
|
* @see OAuth2\GrantType\GrantTypeInterface::createAccessToken()
|
||||||
|
*/
|
||||||
|
public function createAccessToken(AccessTokenInterface $accessToken, $client_id, $user_id, $scope)
|
||||||
|
{
|
||||||
|
$includeRefreshToken = false;
|
||||||
|
|
||||||
|
return $accessToken->createAccessToken($client_id, $user_id, $scope, $includeRefreshToken);
|
||||||
|
}
|
||||||
|
}
|
111
vendor/bshaffer/oauth2-server-php/src/OAuth2/GrantType/RefreshToken.php
vendored
Normal file
111
vendor/bshaffer/oauth2-server-php/src/OAuth2/GrantType/RefreshToken.php
vendored
Normal file
|
@ -0,0 +1,111 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace OAuth2\GrantType;
|
||||||
|
|
||||||
|
use OAuth2\Storage\RefreshTokenInterface;
|
||||||
|
use OAuth2\ResponseType\AccessTokenInterface;
|
||||||
|
use OAuth2\RequestInterface;
|
||||||
|
use OAuth2\ResponseInterface;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @author Brent Shaffer <bshafs at gmail dot com>
|
||||||
|
*/
|
||||||
|
class RefreshToken implements GrantTypeInterface
|
||||||
|
{
|
||||||
|
private $refreshToken;
|
||||||
|
|
||||||
|
protected $storage;
|
||||||
|
protected $config;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param OAuth2\Storage\RefreshTokenInterface $storage REQUIRED Storage class for retrieving refresh token information
|
||||||
|
* @param array $config OPTIONAL Configuration options for the server
|
||||||
|
* <code>
|
||||||
|
* $config = array(
|
||||||
|
* 'always_issue_new_refresh_token' => true, // whether to issue a new refresh token upon successful token request
|
||||||
|
* 'unset_refresh_token_after_use' => true // whether to unset the refresh token after after using
|
||||||
|
* );
|
||||||
|
* </code>
|
||||||
|
*/
|
||||||
|
public function __construct(RefreshTokenInterface $storage, $config = array())
|
||||||
|
{
|
||||||
|
$this->config = array_merge(array(
|
||||||
|
'always_issue_new_refresh_token' => false,
|
||||||
|
'unset_refresh_token_after_use' => true
|
||||||
|
), $config);
|
||||||
|
|
||||||
|
// to preserve B.C. with v1.6
|
||||||
|
// @see https://github.com/bshaffer/oauth2-server-php/pull/580
|
||||||
|
// @todo - remove in v2.0
|
||||||
|
if (isset($config['always_issue_new_refresh_token']) && !isset($config['unset_refresh_token_after_use'])) {
|
||||||
|
$this->config['unset_refresh_token_after_use'] = $config['always_issue_new_refresh_token'];
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->storage = $storage;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getQuerystringIdentifier()
|
||||||
|
{
|
||||||
|
return 'refresh_token';
|
||||||
|
}
|
||||||
|
|
||||||
|
public function validateRequest(RequestInterface $request, ResponseInterface $response)
|
||||||
|
{
|
||||||
|
if (!$request->request("refresh_token")) {
|
||||||
|
$response->setError(400, 'invalid_request', 'Missing parameter: "refresh_token" is required');
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!$refreshToken = $this->storage->getRefreshToken($request->request("refresh_token"))) {
|
||||||
|
$response->setError(400, 'invalid_grant', 'Invalid refresh token');
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($refreshToken['expires'] > 0 && $refreshToken["expires"] < time()) {
|
||||||
|
$response->setError(400, 'invalid_grant', 'Refresh token has expired');
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
// store the refresh token locally so we can delete it when a new refresh token is generated
|
||||||
|
$this->refreshToken = $refreshToken;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getClientId()
|
||||||
|
{
|
||||||
|
return $this->refreshToken['client_id'];
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getUserId()
|
||||||
|
{
|
||||||
|
return isset($this->refreshToken['user_id']) ? $this->refreshToken['user_id'] : null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getScope()
|
||||||
|
{
|
||||||
|
return isset($this->refreshToken['scope']) ? $this->refreshToken['scope'] : null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function createAccessToken(AccessTokenInterface $accessToken, $client_id, $user_id, $scope)
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* It is optional to force a new refresh token when a refresh token is used.
|
||||||
|
* However, if a new refresh token is issued, the old one MUST be expired
|
||||||
|
* @see http://tools.ietf.org/html/rfc6749#section-6
|
||||||
|
*/
|
||||||
|
$issueNewRefreshToken = $this->config['always_issue_new_refresh_token'];
|
||||||
|
$unsetRefreshToken = $this->config['unset_refresh_token_after_use'];
|
||||||
|
$token = $accessToken->createAccessToken($client_id, $user_id, $scope, $issueNewRefreshToken);
|
||||||
|
|
||||||
|
if ($unsetRefreshToken) {
|
||||||
|
$this->storage->unsetRefreshToken($this->refreshToken['refresh_token']);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $token;
|
||||||
|
}
|
||||||
|
}
|
83
vendor/bshaffer/oauth2-server-php/src/OAuth2/GrantType/UserCredentials.php
vendored
Normal file
83
vendor/bshaffer/oauth2-server-php/src/OAuth2/GrantType/UserCredentials.php
vendored
Normal file
|
@ -0,0 +1,83 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace OAuth2\GrantType;
|
||||||
|
|
||||||
|
use OAuth2\Storage\UserCredentialsInterface;
|
||||||
|
use OAuth2\ResponseType\AccessTokenInterface;
|
||||||
|
use OAuth2\RequestInterface;
|
||||||
|
use OAuth2\ResponseInterface;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @author Brent Shaffer <bshafs at gmail dot com>
|
||||||
|
*/
|
||||||
|
class UserCredentials implements GrantTypeInterface
|
||||||
|
{
|
||||||
|
private $userInfo;
|
||||||
|
|
||||||
|
protected $storage;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param OAuth2\Storage\UserCredentialsInterface $storage REQUIRED Storage class for retrieving user credentials information
|
||||||
|
*/
|
||||||
|
public function __construct(UserCredentialsInterface $storage)
|
||||||
|
{
|
||||||
|
$this->storage = $storage;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getQuerystringIdentifier()
|
||||||
|
{
|
||||||
|
return 'password';
|
||||||
|
}
|
||||||
|
|
||||||
|
public function validateRequest(RequestInterface $request, ResponseInterface $response)
|
||||||
|
{
|
||||||
|
if (!$request->request("password") || !$request->request("username")) {
|
||||||
|
$response->setError(400, 'invalid_request', 'Missing parameters: "username" and "password" required');
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!$this->storage->checkUserCredentials($request->request("username"), $request->request("password"))) {
|
||||||
|
$response->setError(401, 'invalid_grant', 'Invalid username and password combination');
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
$userInfo = $this->storage->getUserDetails($request->request("username"));
|
||||||
|
|
||||||
|
if (empty($userInfo)) {
|
||||||
|
$response->setError(400, 'invalid_grant', 'Unable to retrieve user information');
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!isset($userInfo['user_id'])) {
|
||||||
|
throw new \LogicException("you must set the user_id on the array returned by getUserDetails");
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->userInfo = $userInfo;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getClientId()
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getUserId()
|
||||||
|
{
|
||||||
|
return $this->userInfo['user_id'];
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getScope()
|
||||||
|
{
|
||||||
|
return isset($this->userInfo['scope']) ? $this->userInfo['scope'] : null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function createAccessToken(AccessTokenInterface $accessToken, $client_id, $user_id, $scope)
|
||||||
|
{
|
||||||
|
return $accessToken->createAccessToken($client_id, $user_id, $scope);
|
||||||
|
}
|
||||||
|
}
|
106
vendor/bshaffer/oauth2-server-php/src/OAuth2/OpenID/Controller/AuthorizeController.php
vendored
Normal file
106
vendor/bshaffer/oauth2-server-php/src/OAuth2/OpenID/Controller/AuthorizeController.php
vendored
Normal file
|
@ -0,0 +1,106 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace OAuth2\OpenID\Controller;
|
||||||
|
|
||||||
|
use OAuth2\Controller\AuthorizeController as BaseAuthorizeController;
|
||||||
|
use OAuth2\RequestInterface;
|
||||||
|
use OAuth2\ResponseInterface;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @see OAuth2\Controller\AuthorizeControllerInterface
|
||||||
|
*/
|
||||||
|
class AuthorizeController extends BaseAuthorizeController implements AuthorizeControllerInterface
|
||||||
|
{
|
||||||
|
private $nonce;
|
||||||
|
|
||||||
|
protected function setNotAuthorizedResponse(RequestInterface $request, ResponseInterface $response, $redirect_uri, $user_id = null)
|
||||||
|
{
|
||||||
|
$prompt = $request->query('prompt', 'consent');
|
||||||
|
if ($prompt == 'none') {
|
||||||
|
if (is_null($user_id)) {
|
||||||
|
$error = 'login_required';
|
||||||
|
$error_message = 'The user must log in';
|
||||||
|
} else {
|
||||||
|
$error = 'interaction_required';
|
||||||
|
$error_message = 'The user must grant access to your application';
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
$error = 'consent_required';
|
||||||
|
$error_message = 'The user denied access to your application';
|
||||||
|
}
|
||||||
|
|
||||||
|
$response->setRedirect($this->config['redirect_status_code'], $redirect_uri, $this->getState(), $error, $error_message);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function buildAuthorizeParameters($request, $response, $user_id)
|
||||||
|
{
|
||||||
|
if (!$params = parent::buildAuthorizeParameters($request, $response, $user_id)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Generate an id token if needed.
|
||||||
|
if ($this->needsIdToken($this->getScope()) && $this->getResponseType() == self::RESPONSE_TYPE_AUTHORIZATION_CODE) {
|
||||||
|
$params['id_token'] = $this->responseTypes['id_token']->createIdToken($this->getClientId(), $user_id, $this->nonce);
|
||||||
|
}
|
||||||
|
|
||||||
|
// add the nonce to return with the redirect URI
|
||||||
|
$params['nonce'] = $this->nonce;
|
||||||
|
|
||||||
|
return $params;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function validateAuthorizeRequest(RequestInterface $request, ResponseInterface $response)
|
||||||
|
{
|
||||||
|
if (!parent::validateAuthorizeRequest($request, $response)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
$nonce = $request->query('nonce');
|
||||||
|
|
||||||
|
// Validate required nonce for "id_token" and "id_token token"
|
||||||
|
if (!$nonce && in_array($this->getResponseType(), array(self::RESPONSE_TYPE_ID_TOKEN, self::RESPONSE_TYPE_ID_TOKEN_TOKEN))) {
|
||||||
|
$response->setError(400, 'invalid_nonce', 'This application requires you specify a nonce parameter');
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->nonce = $nonce;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function getValidResponseTypes()
|
||||||
|
{
|
||||||
|
return array(
|
||||||
|
self::RESPONSE_TYPE_ACCESS_TOKEN,
|
||||||
|
self::RESPONSE_TYPE_AUTHORIZATION_CODE,
|
||||||
|
self::RESPONSE_TYPE_ID_TOKEN,
|
||||||
|
self::RESPONSE_TYPE_ID_TOKEN_TOKEN,
|
||||||
|
self::RESPONSE_TYPE_CODE_ID_TOKEN,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns whether the current request needs to generate an id token.
|
||||||
|
*
|
||||||
|
* ID Tokens are a part of the OpenID Connect specification, so this
|
||||||
|
* method checks whether OpenID Connect is enabled in the server settings
|
||||||
|
* and whether the openid scope was requested.
|
||||||
|
*
|
||||||
|
* @param $request_scope
|
||||||
|
* A space-separated string of scopes.
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
* TRUE if an id token is needed, FALSE otherwise.
|
||||||
|
*/
|
||||||
|
public function needsIdToken($request_scope)
|
||||||
|
{
|
||||||
|
// see if the "openid" scope exists in the requested scope
|
||||||
|
return $this->scopeUtil->checkScope('openid', $request_scope);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getNonce()
|
||||||
|
{
|
||||||
|
return $this->nonce;
|
||||||
|
}
|
||||||
|
}
|
10
vendor/bshaffer/oauth2-server-php/src/OAuth2/OpenID/Controller/AuthorizeControllerInterface.php
vendored
Normal file
10
vendor/bshaffer/oauth2-server-php/src/OAuth2/OpenID/Controller/AuthorizeControllerInterface.php
vendored
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace OAuth2\OpenID\Controller;
|
||||||
|
|
||||||
|
interface AuthorizeControllerInterface
|
||||||
|
{
|
||||||
|
const RESPONSE_TYPE_ID_TOKEN = 'id_token';
|
||||||
|
const RESPONSE_TYPE_ID_TOKEN_TOKEN = 'id_token token';
|
||||||
|
const RESPONSE_TYPE_CODE_ID_TOKEN = 'code id_token';
|
||||||
|
}
|
58
vendor/bshaffer/oauth2-server-php/src/OAuth2/OpenID/Controller/UserInfoController.php
vendored
Normal file
58
vendor/bshaffer/oauth2-server-php/src/OAuth2/OpenID/Controller/UserInfoController.php
vendored
Normal file
|
@ -0,0 +1,58 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace OAuth2\OpenID\Controller;
|
||||||
|
|
||||||
|
use OAuth2\Scope;
|
||||||
|
use OAuth2\TokenType\TokenTypeInterface;
|
||||||
|
use OAuth2\Storage\AccessTokenInterface;
|
||||||
|
use OAuth2\OpenID\Storage\UserClaimsInterface;
|
||||||
|
use OAuth2\Controller\ResourceController;
|
||||||
|
use OAuth2\ScopeInterface;
|
||||||
|
use OAuth2\RequestInterface;
|
||||||
|
use OAuth2\ResponseInterface;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @see OAuth2\Controller\UserInfoControllerInterface
|
||||||
|
*/
|
||||||
|
class UserInfoController extends ResourceController implements UserInfoControllerInterface
|
||||||
|
{
|
||||||
|
private $token;
|
||||||
|
|
||||||
|
protected $tokenType;
|
||||||
|
protected $tokenStorage;
|
||||||
|
protected $userClaimsStorage;
|
||||||
|
protected $config;
|
||||||
|
protected $scopeUtil;
|
||||||
|
|
||||||
|
public function __construct(TokenTypeInterface $tokenType, AccessTokenInterface $tokenStorage, UserClaimsInterface $userClaimsStorage, $config = array(), ScopeInterface $scopeUtil = null)
|
||||||
|
{
|
||||||
|
$this->tokenType = $tokenType;
|
||||||
|
$this->tokenStorage = $tokenStorage;
|
||||||
|
$this->userClaimsStorage = $userClaimsStorage;
|
||||||
|
|
||||||
|
$this->config = array_merge(array(
|
||||||
|
'www_realm' => 'Service',
|
||||||
|
), $config);
|
||||||
|
|
||||||
|
if (is_null($scopeUtil)) {
|
||||||
|
$scopeUtil = new Scope();
|
||||||
|
}
|
||||||
|
$this->scopeUtil = $scopeUtil;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function handleUserInfoRequest(RequestInterface $request, ResponseInterface $response)
|
||||||
|
{
|
||||||
|
if (!$this->verifyResourceRequest($request, $response, 'openid')) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
$token = $this->getToken();
|
||||||
|
$claims = $this->userClaimsStorage->getUserClaims($token['user_id'], $token['scope']);
|
||||||
|
// The sub Claim MUST always be returned in the UserInfo Response.
|
||||||
|
// http://openid.net/specs/openid-connect-core-1_0.html#UserInfoResponse
|
||||||
|
$claims += array(
|
||||||
|
'sub' => $token['user_id'],
|
||||||
|
);
|
||||||
|
$response->addParameters($claims);
|
||||||
|
}
|
||||||
|
}
|
23
vendor/bshaffer/oauth2-server-php/src/OAuth2/OpenID/Controller/UserInfoControllerInterface.php
vendored
Normal file
23
vendor/bshaffer/oauth2-server-php/src/OAuth2/OpenID/Controller/UserInfoControllerInterface.php
vendored
Normal file
|
@ -0,0 +1,23 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace OAuth2\OpenID\Controller;
|
||||||
|
|
||||||
|
use OAuth2\RequestInterface;
|
||||||
|
use OAuth2\ResponseInterface;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This controller is called when the user claims for OpenID Connect's
|
||||||
|
* UserInfo endpoint should be returned.
|
||||||
|
*
|
||||||
|
* ex:
|
||||||
|
* > $response = new OAuth2\Response();
|
||||||
|
* > $userInfoController->handleUserInfoRequest(
|
||||||
|
* > OAuth2\Request::createFromGlobals(),
|
||||||
|
* > $response;
|
||||||
|
* > $response->send();
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
interface UserInfoControllerInterface
|
||||||
|
{
|
||||||
|
public function handleUserInfoRequest(RequestInterface $request, ResponseInterface $response);
|
||||||
|
}
|
33
vendor/bshaffer/oauth2-server-php/src/OAuth2/OpenID/GrantType/AuthorizationCode.php
vendored
Normal file
33
vendor/bshaffer/oauth2-server-php/src/OAuth2/OpenID/GrantType/AuthorizationCode.php
vendored
Normal file
|
@ -0,0 +1,33 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace OAuth2\OpenID\GrantType;
|
||||||
|
|
||||||
|
use OAuth2\GrantType\AuthorizationCode as BaseAuthorizationCode;
|
||||||
|
use OAuth2\ResponseType\AccessTokenInterface;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @author Brent Shaffer <bshafs at gmail dot com>
|
||||||
|
*/
|
||||||
|
class AuthorizationCode extends BaseAuthorizationCode
|
||||||
|
{
|
||||||
|
public function createAccessToken(AccessTokenInterface $accessToken, $client_id, $user_id, $scope)
|
||||||
|
{
|
||||||
|
$includeRefreshToken = true;
|
||||||
|
if (isset($this->authCode['id_token'])) {
|
||||||
|
// OpenID Connect requests include the refresh token only if the
|
||||||
|
// offline_access scope has been requested and granted.
|
||||||
|
$scopes = explode(' ', trim($scope));
|
||||||
|
$includeRefreshToken = in_array('offline_access', $scopes);
|
||||||
|
}
|
||||||
|
|
||||||
|
$token = $accessToken->createAccessToken($client_id, $user_id, $scope, $includeRefreshToken);
|
||||||
|
if (isset($this->authCode['id_token'])) {
|
||||||
|
$token['id_token'] = $this->authCode['id_token'];
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->storage->expireAuthorizationCode($this->authCode['code']);
|
||||||
|
|
||||||
|
return $token;
|
||||||
|
}
|
||||||
|
}
|
60
vendor/bshaffer/oauth2-server-php/src/OAuth2/OpenID/ResponseType/AuthorizationCode.php
vendored
Normal file
60
vendor/bshaffer/oauth2-server-php/src/OAuth2/OpenID/ResponseType/AuthorizationCode.php
vendored
Normal file
|
@ -0,0 +1,60 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace OAuth2\OpenID\ResponseType;
|
||||||
|
|
||||||
|
use OAuth2\ResponseType\AuthorizationCode as BaseAuthorizationCode;
|
||||||
|
use OAuth2\OpenID\Storage\AuthorizationCodeInterface as AuthorizationCodeStorageInterface;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @author Brent Shaffer <bshafs at gmail dot com>
|
||||||
|
*/
|
||||||
|
class AuthorizationCode extends BaseAuthorizationCode implements AuthorizationCodeInterface
|
||||||
|
{
|
||||||
|
public function __construct(AuthorizationCodeStorageInterface $storage, array $config = array())
|
||||||
|
{
|
||||||
|
parent::__construct($storage, $config);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getAuthorizeResponse($params, $user_id = null)
|
||||||
|
{
|
||||||
|
// build the URL to redirect to
|
||||||
|
$result = array('query' => array());
|
||||||
|
|
||||||
|
$params += array('scope' => null, 'state' => null, 'id_token' => null);
|
||||||
|
|
||||||
|
$result['query']['code'] = $this->createAuthorizationCode($params['client_id'], $user_id, $params['redirect_uri'], $params['scope'], $params['id_token']);
|
||||||
|
|
||||||
|
if (isset($params['state'])) {
|
||||||
|
$result['query']['state'] = $params['state'];
|
||||||
|
}
|
||||||
|
|
||||||
|
return array($params['redirect_uri'], $result);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handle the creation of the authorization code.
|
||||||
|
*
|
||||||
|
* @param $client_id
|
||||||
|
* Client identifier related to the authorization code
|
||||||
|
* @param $user_id
|
||||||
|
* User ID associated with the authorization code
|
||||||
|
* @param $redirect_uri
|
||||||
|
* An absolute URI to which the authorization server will redirect the
|
||||||
|
* user-agent to when the end-user authorization step is completed.
|
||||||
|
* @param $scope
|
||||||
|
* (optional) Scopes to be stored in space-separated string.
|
||||||
|
* @param $id_token
|
||||||
|
* (optional) The OpenID Connect id_token.
|
||||||
|
*
|
||||||
|
* @see http://tools.ietf.org/html/rfc6749#section-4
|
||||||
|
* @ingroup oauth2_section_4
|
||||||
|
*/
|
||||||
|
public function createAuthorizationCode($client_id, $user_id, $redirect_uri, $scope = null, $id_token = null)
|
||||||
|
{
|
||||||
|
$code = $this->generateAuthorizationCode();
|
||||||
|
$this->storage->setAuthorizationCode($code, $client_id, $user_id, $redirect_uri, time() + $this->config['auth_code_lifetime'], $scope, $id_token);
|
||||||
|
|
||||||
|
return $code;
|
||||||
|
}
|
||||||
|
}
|
27
vendor/bshaffer/oauth2-server-php/src/OAuth2/OpenID/ResponseType/AuthorizationCodeInterface.php
vendored
Normal file
27
vendor/bshaffer/oauth2-server-php/src/OAuth2/OpenID/ResponseType/AuthorizationCodeInterface.php
vendored
Normal file
|
@ -0,0 +1,27 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace OAuth2\OpenID\ResponseType;
|
||||||
|
|
||||||
|
use OAuth2\ResponseType\AuthorizationCodeInterface as BaseAuthorizationCodeInterface;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @author Brent Shaffer <bshafs at gmail dot com>
|
||||||
|
*/
|
||||||
|
interface AuthorizationCodeInterface extends BaseAuthorizationCodeInterface
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Handle the creation of the authorization code.
|
||||||
|
*
|
||||||
|
* @param $client_id Client identifier related to the authorization code
|
||||||
|
* @param $user_id User ID associated with the authorization code
|
||||||
|
* @param $redirect_uri An absolute URI to which the authorization server will redirect the
|
||||||
|
* user-agent to when the end-user authorization step is completed.
|
||||||
|
* @param $scope OPTIONAL Scopes to be stored in space-separated string.
|
||||||
|
* @param $id_token OPTIONAL The OpenID Connect id_token.
|
||||||
|
*
|
||||||
|
* @see http://tools.ietf.org/html/rfc6749#section-4
|
||||||
|
* @ingroup oauth2_section_4
|
||||||
|
*/
|
||||||
|
public function createAuthorizationCode($client_id, $user_id, $redirect_uri, $scope = null, $id_token = null);
|
||||||
|
}
|
24
vendor/bshaffer/oauth2-server-php/src/OAuth2/OpenID/ResponseType/CodeIdToken.php
vendored
Normal file
24
vendor/bshaffer/oauth2-server-php/src/OAuth2/OpenID/ResponseType/CodeIdToken.php
vendored
Normal file
|
@ -0,0 +1,24 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace OAuth2\OpenID\ResponseType;
|
||||||
|
|
||||||
|
class CodeIdToken implements CodeIdTokenInterface
|
||||||
|
{
|
||||||
|
protected $authCode;
|
||||||
|
protected $idToken;
|
||||||
|
|
||||||
|
public function __construct(AuthorizationCodeInterface $authCode, IdTokenInterface $idToken)
|
||||||
|
{
|
||||||
|
$this->authCode = $authCode;
|
||||||
|
$this->idToken = $idToken;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getAuthorizeResponse($params, $user_id = null)
|
||||||
|
{
|
||||||
|
$result = $this->authCode->getAuthorizeResponse($params, $user_id);
|
||||||
|
$id_token = $this->idToken->createIdToken($params['client_id'], $user_id, $params['nonce']);
|
||||||
|
$result[1]['query']['id_token'] = $id_token;
|
||||||
|
|
||||||
|
return $result;
|
||||||
|
}
|
||||||
|
}
|
9
vendor/bshaffer/oauth2-server-php/src/OAuth2/OpenID/ResponseType/CodeIdTokenInterface.php
vendored
Normal file
9
vendor/bshaffer/oauth2-server-php/src/OAuth2/OpenID/ResponseType/CodeIdTokenInterface.php
vendored
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace OAuth2\OpenID\ResponseType;
|
||||||
|
|
||||||
|
use OAuth2\ResponseType\ResponseTypeInterface;
|
||||||
|
|
||||||
|
interface CodeIdTokenInterface extends ResponseTypeInterface
|
||||||
|
{
|
||||||
|
}
|
124
vendor/bshaffer/oauth2-server-php/src/OAuth2/OpenID/ResponseType/IdToken.php
vendored
Normal file
124
vendor/bshaffer/oauth2-server-php/src/OAuth2/OpenID/ResponseType/IdToken.php
vendored
Normal file
|
@ -0,0 +1,124 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace OAuth2\OpenID\ResponseType;
|
||||||
|
|
||||||
|
use OAuth2\Encryption\EncryptionInterface;
|
||||||
|
use OAuth2\Encryption\Jwt;
|
||||||
|
use OAuth2\Storage\PublicKeyInterface;
|
||||||
|
use OAuth2\OpenID\Storage\UserClaimsInterface;
|
||||||
|
|
||||||
|
class IdToken implements IdTokenInterface
|
||||||
|
{
|
||||||
|
protected $userClaimsStorage;
|
||||||
|
protected $publicKeyStorage;
|
||||||
|
protected $config;
|
||||||
|
protected $encryptionUtil;
|
||||||
|
|
||||||
|
public function __construct(UserClaimsInterface $userClaimsStorage, PublicKeyInterface $publicKeyStorage, array $config = array(), EncryptionInterface $encryptionUtil = null)
|
||||||
|
{
|
||||||
|
$this->userClaimsStorage = $userClaimsStorage;
|
||||||
|
$this->publicKeyStorage = $publicKeyStorage;
|
||||||
|
if (is_null($encryptionUtil)) {
|
||||||
|
$encryptionUtil = new Jwt();
|
||||||
|
}
|
||||||
|
$this->encryptionUtil = $encryptionUtil;
|
||||||
|
|
||||||
|
if (!isset($config['issuer'])) {
|
||||||
|
throw new \LogicException('config parameter "issuer" must be set');
|
||||||
|
}
|
||||||
|
$this->config = array_merge(array(
|
||||||
|
'id_lifetime' => 3600,
|
||||||
|
), $config);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getAuthorizeResponse($params, $userInfo = null)
|
||||||
|
{
|
||||||
|
// build the URL to redirect to
|
||||||
|
$result = array('query' => array());
|
||||||
|
$params += array('scope' => null, 'state' => null, 'nonce' => null);
|
||||||
|
|
||||||
|
// create the id token.
|
||||||
|
list($user_id, $auth_time) = $this->getUserIdAndAuthTime($userInfo);
|
||||||
|
$userClaims = $this->userClaimsStorage->getUserClaims($user_id, $params['scope']);
|
||||||
|
|
||||||
|
$id_token = $this->createIdToken($params['client_id'], $userInfo, $params['nonce'], $userClaims, null);
|
||||||
|
$result["fragment"] = array('id_token' => $id_token);
|
||||||
|
if (isset($params['state'])) {
|
||||||
|
$result["fragment"]["state"] = $params['state'];
|
||||||
|
}
|
||||||
|
|
||||||
|
return array($params['redirect_uri'], $result);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function createIdToken($client_id, $userInfo, $nonce = null, $userClaims = null, $access_token = null)
|
||||||
|
{
|
||||||
|
// pull auth_time from user info if supplied
|
||||||
|
list($user_id, $auth_time) = $this->getUserIdAndAuthTime($userInfo);
|
||||||
|
|
||||||
|
$token = array(
|
||||||
|
'iss' => $this->config['issuer'],
|
||||||
|
'sub' => $user_id,
|
||||||
|
'aud' => $client_id,
|
||||||
|
'iat' => time(),
|
||||||
|
'exp' => time() + $this->config['id_lifetime'],
|
||||||
|
'auth_time' => $auth_time,
|
||||||
|
);
|
||||||
|
|
||||||
|
if ($nonce) {
|
||||||
|
$token['nonce'] = $nonce;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($userClaims) {
|
||||||
|
$token += $userClaims;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($access_token) {
|
||||||
|
$token['at_hash'] = $this->createAtHash($access_token, $client_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this->encodeToken($token, $client_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function createAtHash($access_token, $client_id = null)
|
||||||
|
{
|
||||||
|
// maps HS256 and RS256 to sha256, etc.
|
||||||
|
$algorithm = $this->publicKeyStorage->getEncryptionAlgorithm($client_id);
|
||||||
|
$hash_algorithm = 'sha' . substr($algorithm, 2);
|
||||||
|
$hash = hash($hash_algorithm, $access_token);
|
||||||
|
$at_hash = substr($hash, 0, strlen($hash) / 2);
|
||||||
|
|
||||||
|
return $this->encryptionUtil->urlSafeB64Encode($at_hash);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function encodeToken(array $token, $client_id = null)
|
||||||
|
{
|
||||||
|
$private_key = $this->publicKeyStorage->getPrivateKey($client_id);
|
||||||
|
$algorithm = $this->publicKeyStorage->getEncryptionAlgorithm($client_id);
|
||||||
|
|
||||||
|
return $this->encryptionUtil->encode($token, $private_key, $algorithm);
|
||||||
|
}
|
||||||
|
|
||||||
|
private function getUserIdAndAuthTime($userInfo)
|
||||||
|
{
|
||||||
|
$auth_time = null;
|
||||||
|
|
||||||
|
// support an array for user_id / auth_time
|
||||||
|
if (is_array($userInfo)) {
|
||||||
|
if (!isset($userInfo['user_id'])) {
|
||||||
|
throw new \LogicException('if $user_id argument is an array, user_id index must be set');
|
||||||
|
}
|
||||||
|
|
||||||
|
$auth_time = isset($userInfo['auth_time']) ? $userInfo['auth_time'] : null;
|
||||||
|
$user_id = $userInfo['user_id'];
|
||||||
|
} else {
|
||||||
|
$user_id = $userInfo;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (is_null($auth_time)) {
|
||||||
|
$auth_time = time();
|
||||||
|
}
|
||||||
|
|
||||||
|
// userInfo is a scalar, and so this is the $user_id. Auth Time is null
|
||||||
|
return array($user_id, $auth_time);
|
||||||
|
}
|
||||||
|
}
|
29
vendor/bshaffer/oauth2-server-php/src/OAuth2/OpenID/ResponseType/IdTokenInterface.php
vendored
Normal file
29
vendor/bshaffer/oauth2-server-php/src/OAuth2/OpenID/ResponseType/IdTokenInterface.php
vendored
Normal file
|
@ -0,0 +1,29 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace OAuth2\OpenID\ResponseType;
|
||||||
|
|
||||||
|
use OAuth2\ResponseType\ResponseTypeInterface;
|
||||||
|
|
||||||
|
interface IdTokenInterface extends ResponseTypeInterface
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Create the id token.
|
||||||
|
*
|
||||||
|
* If Authorization Code Flow is used, the id_token is generated when the
|
||||||
|
* authorization code is issued, and later returned from the token endpoint
|
||||||
|
* together with the access_token.
|
||||||
|
* If the Implicit Flow is used, the token and id_token are generated and
|
||||||
|
* returned together.
|
||||||
|
*
|
||||||
|
* @param string $client_id The client id.
|
||||||
|
* @param string $user_id The user id.
|
||||||
|
* @param string $nonce OPTIONAL The nonce.
|
||||||
|
* @param string $userClaims OPTIONAL Claims about the user.
|
||||||
|
* @param string $access_token OPTIONAL The access token, if known.
|
||||||
|
*
|
||||||
|
* @return string The ID Token represented as a JSON Web Token (JWT).
|
||||||
|
*
|
||||||
|
* @see http://openid.net/specs/openid-connect-core-1_0.html#IDToken
|
||||||
|
*/
|
||||||
|
public function createIdToken($client_id, $userInfo, $nonce = null, $userClaims = null, $access_token = null);
|
||||||
|
}
|
27
vendor/bshaffer/oauth2-server-php/src/OAuth2/OpenID/ResponseType/IdTokenToken.php
vendored
Normal file
27
vendor/bshaffer/oauth2-server-php/src/OAuth2/OpenID/ResponseType/IdTokenToken.php
vendored
Normal file
|
@ -0,0 +1,27 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace OAuth2\OpenID\ResponseType;
|
||||||
|
|
||||||
|
use OAuth2\ResponseType\AccessTokenInterface;
|
||||||
|
|
||||||
|
class IdTokenToken implements IdTokenTokenInterface
|
||||||
|
{
|
||||||
|
protected $accessToken;
|
||||||
|
protected $idToken;
|
||||||
|
|
||||||
|
public function __construct(AccessTokenInterface $accessToken, IdTokenInterface $idToken)
|
||||||
|
{
|
||||||
|
$this->accessToken = $accessToken;
|
||||||
|
$this->idToken = $idToken;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getAuthorizeResponse($params, $user_id = null)
|
||||||
|
{
|
||||||
|
$result = $this->accessToken->getAuthorizeResponse($params, $user_id);
|
||||||
|
$access_token = $result[1]['fragment']['access_token'];
|
||||||
|
$id_token = $this->idToken->createIdToken($params['client_id'], $user_id, $params['nonce'], null, $access_token);
|
||||||
|
$result[1]['fragment']['id_token'] = $id_token;
|
||||||
|
|
||||||
|
return $result;
|
||||||
|
}
|
||||||
|
}
|
9
vendor/bshaffer/oauth2-server-php/src/OAuth2/OpenID/ResponseType/IdTokenTokenInterface.php
vendored
Normal file
9
vendor/bshaffer/oauth2-server-php/src/OAuth2/OpenID/ResponseType/IdTokenTokenInterface.php
vendored
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace OAuth2\OpenID\ResponseType;
|
||||||
|
|
||||||
|
use OAuth2\ResponseType\ResponseTypeInterface;
|
||||||
|
|
||||||
|
interface IdTokenTokenInterface extends ResponseTypeInterface
|
||||||
|
{
|
||||||
|
}
|
37
vendor/bshaffer/oauth2-server-php/src/OAuth2/OpenID/Storage/AuthorizationCodeInterface.php
vendored
Normal file
37
vendor/bshaffer/oauth2-server-php/src/OAuth2/OpenID/Storage/AuthorizationCodeInterface.php
vendored
Normal file
|
@ -0,0 +1,37 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace OAuth2\OpenID\Storage;
|
||||||
|
|
||||||
|
use OAuth2\Storage\AuthorizationCodeInterface as BaseAuthorizationCodeInterface;
|
||||||
|
/**
|
||||||
|
* Implement this interface to specify where the OAuth2 Server
|
||||||
|
* should get/save authorization codes for the "Authorization Code"
|
||||||
|
* grant type
|
||||||
|
*
|
||||||
|
* @author Brent Shaffer <bshafs at gmail dot com>
|
||||||
|
*/
|
||||||
|
interface AuthorizationCodeInterface extends BaseAuthorizationCodeInterface
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Take the provided authorization code values and store them somewhere.
|
||||||
|
*
|
||||||
|
* This function should be the storage counterpart to getAuthCode().
|
||||||
|
*
|
||||||
|
* If storage fails for some reason, we're not currently checking for
|
||||||
|
* any sort of success/failure, so you should bail out of the script
|
||||||
|
* and provide a descriptive fail message.
|
||||||
|
*
|
||||||
|
* Required for OAuth2::GRANT_TYPE_AUTH_CODE.
|
||||||
|
*
|
||||||
|
* @param $code authorization code to be stored.
|
||||||
|
* @param $client_id client identifier to be stored.
|
||||||
|
* @param $user_id user identifier to be stored.
|
||||||
|
* @param string $redirect_uri redirect URI(s) to be stored in a space-separated string.
|
||||||
|
* @param int $expires expiration to be stored as a Unix timestamp.
|
||||||
|
* @param string $scope OPTIONAL scopes to be stored in space-separated string.
|
||||||
|
* @param string $id_token OPTIONAL the OpenID Connect id_token.
|
||||||
|
*
|
||||||
|
* @ingroup oauth2_section_4
|
||||||
|
*/
|
||||||
|
public function setAuthorizationCode($code, $client_id, $user_id, $redirect_uri, $expires, $scope = null, $id_token = null);
|
||||||
|
}
|
38
vendor/bshaffer/oauth2-server-php/src/OAuth2/OpenID/Storage/UserClaimsInterface.php
vendored
Normal file
38
vendor/bshaffer/oauth2-server-php/src/OAuth2/OpenID/Storage/UserClaimsInterface.php
vendored
Normal file
|
@ -0,0 +1,38 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace OAuth2\OpenID\Storage;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Implement this interface to specify where the OAuth2 Server
|
||||||
|
* should retrieve user claims for the OpenID Connect id_token.
|
||||||
|
*/
|
||||||
|
interface UserClaimsInterface
|
||||||
|
{
|
||||||
|
// valid scope values to pass into the user claims API call
|
||||||
|
const VALID_CLAIMS = 'profile email address phone';
|
||||||
|
|
||||||
|
// fields returned for the claims above
|
||||||
|
const PROFILE_CLAIM_VALUES = 'name family_name given_name middle_name nickname preferred_username profile picture website gender birthdate zoneinfo locale updated_at';
|
||||||
|
const EMAIL_CLAIM_VALUES = 'email email_verified';
|
||||||
|
const ADDRESS_CLAIM_VALUES = 'formatted street_address locality region postal_code country';
|
||||||
|
const PHONE_CLAIM_VALUES = 'phone_number phone_number_verified';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return claims about the provided user id.
|
||||||
|
*
|
||||||
|
* Groups of claims are returned based on the requested scopes. No group
|
||||||
|
* is required, and no claim is required.
|
||||||
|
*
|
||||||
|
* @param $user_id
|
||||||
|
* The id of the user for which claims should be returned.
|
||||||
|
* @param $scope
|
||||||
|
* The requested scope.
|
||||||
|
* Scopes with matching claims: profile, email, address, phone.
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
* An array in the claim => value format.
|
||||||
|
*
|
||||||
|
* @see http://openid.net/specs/openid-connect-core-1_0.html#ScopeClaims
|
||||||
|
*/
|
||||||
|
public function getUserClaims($user_id, $scope);
|
||||||
|
}
|
213
vendor/bshaffer/oauth2-server-php/src/OAuth2/Request.php
vendored
Normal file
213
vendor/bshaffer/oauth2-server-php/src/OAuth2/Request.php
vendored
Normal file
|
@ -0,0 +1,213 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace OAuth2;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* OAuth2\Request
|
||||||
|
* This class is taken from the Symfony2 Framework and is part of the Symfony package.
|
||||||
|
* See Symfony\Component\HttpFoundation\Request (https://github.com/symfony/symfony)
|
||||||
|
*/
|
||||||
|
class Request implements RequestInterface
|
||||||
|
{
|
||||||
|
public $attributes;
|
||||||
|
public $request;
|
||||||
|
public $query;
|
||||||
|
public $server;
|
||||||
|
public $files;
|
||||||
|
public $cookies;
|
||||||
|
public $headers;
|
||||||
|
public $content;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructor.
|
||||||
|
*
|
||||||
|
* @param array $query The GET parameters
|
||||||
|
* @param array $request The POST parameters
|
||||||
|
* @param array $attributes The request attributes (parameters parsed from the PATH_INFO, ...)
|
||||||
|
* @param array $cookies The COOKIE parameters
|
||||||
|
* @param array $files The FILES parameters
|
||||||
|
* @param array $server The SERVER parameters
|
||||||
|
* @param string $content The raw body data
|
||||||
|
*
|
||||||
|
* @api
|
||||||
|
*/
|
||||||
|
public function __construct(array $query = array(), array $request = array(), array $attributes = array(), array $cookies = array(), array $files = array(), array $server = array(), $content = null, array $headers = null)
|
||||||
|
{
|
||||||
|
$this->initialize($query, $request, $attributes, $cookies, $files, $server, $content, $headers);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the parameters for this request.
|
||||||
|
*
|
||||||
|
* This method also re-initializes all properties.
|
||||||
|
*
|
||||||
|
* @param array $query The GET parameters
|
||||||
|
* @param array $request The POST parameters
|
||||||
|
* @param array $attributes The request attributes (parameters parsed from the PATH_INFO, ...)
|
||||||
|
* @param array $cookies The COOKIE parameters
|
||||||
|
* @param array $files The FILES parameters
|
||||||
|
* @param array $server The SERVER parameters
|
||||||
|
* @param string $content The raw body data
|
||||||
|
*
|
||||||
|
* @api
|
||||||
|
*/
|
||||||
|
public function initialize(array $query = array(), array $request = array(), array $attributes = array(), array $cookies = array(), array $files = array(), array $server = array(), $content = null, array $headers = null)
|
||||||
|
{
|
||||||
|
$this->request = $request;
|
||||||
|
$this->query = $query;
|
||||||
|
$this->attributes = $attributes;
|
||||||
|
$this->cookies = $cookies;
|
||||||
|
$this->files = $files;
|
||||||
|
$this->server = $server;
|
||||||
|
$this->content = $content;
|
||||||
|
$this->headers = is_null($headers) ? $this->getHeadersFromServer($this->server) : $headers;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function query($name, $default = null)
|
||||||
|
{
|
||||||
|
return isset($this->query[$name]) ? $this->query[$name] : $default;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function request($name, $default = null)
|
||||||
|
{
|
||||||
|
return isset($this->request[$name]) ? $this->request[$name] : $default;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function server($name, $default = null)
|
||||||
|
{
|
||||||
|
return isset($this->server[$name]) ? $this->server[$name] : $default;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function headers($name, $default = null)
|
||||||
|
{
|
||||||
|
$headers = array_change_key_case($this->headers);
|
||||||
|
$name = strtolower($name);
|
||||||
|
|
||||||
|
return isset($headers[$name]) ? $headers[$name] : $default;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getAllQueryParameters()
|
||||||
|
{
|
||||||
|
return $this->query;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the request body content.
|
||||||
|
*
|
||||||
|
* @param Boolean $asResource If true, a resource will be returned
|
||||||
|
*
|
||||||
|
* @return string|resource The request body content or a resource to read the body stream.
|
||||||
|
*/
|
||||||
|
public function getContent($asResource = false)
|
||||||
|
{
|
||||||
|
if (false === $this->content || (true === $asResource && null !== $this->content)) {
|
||||||
|
throw new \LogicException('getContent() can only be called once when using the resource return type.');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (true === $asResource) {
|
||||||
|
$this->content = false;
|
||||||
|
|
||||||
|
return fopen('php://input', 'rb');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (null === $this->content) {
|
||||||
|
$this->content = file_get_contents('php://input');
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this->content;
|
||||||
|
}
|
||||||
|
|
||||||
|
private function getHeadersFromServer($server)
|
||||||
|
{
|
||||||
|
$headers = array();
|
||||||
|
foreach ($server as $key => $value) {
|
||||||
|
if (0 === strpos($key, 'HTTP_')) {
|
||||||
|
$headers[substr($key, 5)] = $value;
|
||||||
|
}
|
||||||
|
// CONTENT_* are not prefixed with HTTP_
|
||||||
|
elseif (in_array($key, array('CONTENT_LENGTH', 'CONTENT_MD5', 'CONTENT_TYPE'))) {
|
||||||
|
$headers[$key] = $value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isset($server['PHP_AUTH_USER'])) {
|
||||||
|
$headers['PHP_AUTH_USER'] = $server['PHP_AUTH_USER'];
|
||||||
|
$headers['PHP_AUTH_PW'] = isset($server['PHP_AUTH_PW']) ? $server['PHP_AUTH_PW'] : '';
|
||||||
|
} else {
|
||||||
|
/*
|
||||||
|
* php-cgi under Apache does not pass HTTP Basic user/pass to PHP by default
|
||||||
|
* For this workaround to work, add this line to your .htaccess file:
|
||||||
|
* RewriteRule .* - [E=HTTP_AUTHORIZATION:%{HTTP:Authorization}]
|
||||||
|
*
|
||||||
|
* A sample .htaccess file:
|
||||||
|
* RewriteEngine On
|
||||||
|
* RewriteRule .* - [E=HTTP_AUTHORIZATION:%{HTTP:Authorization}]
|
||||||
|
* RewriteCond %{REQUEST_FILENAME} !-f
|
||||||
|
* RewriteRule ^(.*)$ app.php [QSA,L]
|
||||||
|
*/
|
||||||
|
|
||||||
|
$authorizationHeader = null;
|
||||||
|
if (isset($server['HTTP_AUTHORIZATION'])) {
|
||||||
|
$authorizationHeader = $server['HTTP_AUTHORIZATION'];
|
||||||
|
} elseif (isset($server['REDIRECT_HTTP_AUTHORIZATION'])) {
|
||||||
|
$authorizationHeader = $server['REDIRECT_HTTP_AUTHORIZATION'];
|
||||||
|
} elseif (function_exists('apache_request_headers')) {
|
||||||
|
$requestHeaders = (array) apache_request_headers();
|
||||||
|
|
||||||
|
// Server-side fix for bug in old Android versions (a nice side-effect of this fix means we don't care about capitalization for Authorization)
|
||||||
|
$requestHeaders = array_combine(array_map('ucwords', array_keys($requestHeaders)), array_values($requestHeaders));
|
||||||
|
|
||||||
|
if (isset($requestHeaders['Authorization'])) {
|
||||||
|
$authorizationHeader = trim($requestHeaders['Authorization']);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (null !== $authorizationHeader) {
|
||||||
|
$headers['AUTHORIZATION'] = $authorizationHeader;
|
||||||
|
// Decode AUTHORIZATION header into PHP_AUTH_USER and PHP_AUTH_PW when authorization header is basic
|
||||||
|
if (0 === stripos($authorizationHeader, 'basic')) {
|
||||||
|
$exploded = explode(':', base64_decode(substr($authorizationHeader, 6)));
|
||||||
|
if (count($exploded) == 2) {
|
||||||
|
list($headers['PHP_AUTH_USER'], $headers['PHP_AUTH_PW']) = $exploded;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// PHP_AUTH_USER/PHP_AUTH_PW
|
||||||
|
if (isset($headers['PHP_AUTH_USER'])) {
|
||||||
|
$headers['AUTHORIZATION'] = 'Basic '.base64_encode($headers['PHP_AUTH_USER'].':'.$headers['PHP_AUTH_PW']);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $headers;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a new request with values from PHP's super globals.
|
||||||
|
*
|
||||||
|
* @return Request A new request
|
||||||
|
*
|
||||||
|
* @api
|
||||||
|
*/
|
||||||
|
public static function createFromGlobals()
|
||||||
|
{
|
||||||
|
$class = get_called_class();
|
||||||
|
$request = new $class($_GET, $_POST, array(), $_COOKIE, $_FILES, $_SERVER);
|
||||||
|
|
||||||
|
$contentType = $request->server('CONTENT_TYPE', '');
|
||||||
|
$requestMethod = $request->server('REQUEST_METHOD', 'GET');
|
||||||
|
if (0 === strpos($contentType, 'application/x-www-form-urlencoded')
|
||||||
|
&& in_array(strtoupper($requestMethod), array('PUT', 'DELETE'))
|
||||||
|
) {
|
||||||
|
parse_str($request->getContent(), $data);
|
||||||
|
$request->request = $data;
|
||||||
|
} elseif (0 === strpos($contentType, 'application/json')
|
||||||
|
&& in_array(strtoupper($requestMethod), array('POST', 'PUT', 'DELETE'))
|
||||||
|
) {
|
||||||
|
$data = json_decode($request->getContent(), true);
|
||||||
|
$request->request = $data;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $request;
|
||||||
|
}
|
||||||
|
}
|
16
vendor/bshaffer/oauth2-server-php/src/OAuth2/RequestInterface.php
vendored
Normal file
16
vendor/bshaffer/oauth2-server-php/src/OAuth2/RequestInterface.php
vendored
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace OAuth2;
|
||||||
|
|
||||||
|
interface RequestInterface
|
||||||
|
{
|
||||||
|
public function query($name, $default = null);
|
||||||
|
|
||||||
|
public function request($name, $default = null);
|
||||||
|
|
||||||
|
public function server($name, $default = null);
|
||||||
|
|
||||||
|
public function headers($name, $default = null);
|
||||||
|
|
||||||
|
public function getAllQueryParameters();
|
||||||
|
}
|
369
vendor/bshaffer/oauth2-server-php/src/OAuth2/Response.php
vendored
Normal file
369
vendor/bshaffer/oauth2-server-php/src/OAuth2/Response.php
vendored
Normal file
|
@ -0,0 +1,369 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace OAuth2;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class to handle OAuth2 Responses in a graceful way. Use this interface
|
||||||
|
* to output the proper OAuth2 responses.
|
||||||
|
*
|
||||||
|
* @see OAuth2\ResponseInterface
|
||||||
|
*
|
||||||
|
* This class borrows heavily from the Symfony2 Framework and is part of the symfony package
|
||||||
|
* @see Symfony\Component\HttpFoundation\Request (https://github.com/symfony/symfony)
|
||||||
|
*/
|
||||||
|
class Response implements ResponseInterface
|
||||||
|
{
|
||||||
|
public $version;
|
||||||
|
protected $statusCode = 200;
|
||||||
|
protected $statusText;
|
||||||
|
protected $parameters = array();
|
||||||
|
protected $httpHeaders = array();
|
||||||
|
|
||||||
|
public static $statusTexts = array(
|
||||||
|
100 => 'Continue',
|
||||||
|
101 => 'Switching Protocols',
|
||||||
|
200 => 'OK',
|
||||||
|
201 => 'Created',
|
||||||
|
202 => 'Accepted',
|
||||||
|
203 => 'Non-Authoritative Information',
|
||||||
|
204 => 'No Content',
|
||||||
|
205 => 'Reset Content',
|
||||||
|
206 => 'Partial Content',
|
||||||
|
300 => 'Multiple Choices',
|
||||||
|
301 => 'Moved Permanently',
|
||||||
|
302 => 'Found',
|
||||||
|
303 => 'See Other',
|
||||||
|
304 => 'Not Modified',
|
||||||
|
305 => 'Use Proxy',
|
||||||
|
307 => 'Temporary Redirect',
|
||||||
|
400 => 'Bad Request',
|
||||||
|
401 => 'Unauthorized',
|
||||||
|
402 => 'Payment Required',
|
||||||
|
403 => 'Forbidden',
|
||||||
|
404 => 'Not Found',
|
||||||
|
405 => 'Method Not Allowed',
|
||||||
|
406 => 'Not Acceptable',
|
||||||
|
407 => 'Proxy Authentication Required',
|
||||||
|
408 => 'Request Timeout',
|
||||||
|
409 => 'Conflict',
|
||||||
|
410 => 'Gone',
|
||||||
|
411 => 'Length Required',
|
||||||
|
412 => 'Precondition Failed',
|
||||||
|
413 => 'Request Entity Too Large',
|
||||||
|
414 => 'Request-URI Too Long',
|
||||||
|
415 => 'Unsupported Media Type',
|
||||||
|
416 => 'Requested Range Not Satisfiable',
|
||||||
|
417 => 'Expectation Failed',
|
||||||
|
418 => 'I\'m a teapot',
|
||||||
|
500 => 'Internal Server Error',
|
||||||
|
501 => 'Not Implemented',
|
||||||
|
502 => 'Bad Gateway',
|
||||||
|
503 => 'Service Unavailable',
|
||||||
|
504 => 'Gateway Timeout',
|
||||||
|
505 => 'HTTP Version Not Supported',
|
||||||
|
);
|
||||||
|
|
||||||
|
public function __construct($parameters = array(), $statusCode = 200, $headers = array())
|
||||||
|
{
|
||||||
|
$this->setParameters($parameters);
|
||||||
|
$this->setStatusCode($statusCode);
|
||||||
|
$this->setHttpHeaders($headers);
|
||||||
|
$this->version = '1.1';
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Converts the response object to string containing all headers and the response content.
|
||||||
|
*
|
||||||
|
* @return string The response with headers and content
|
||||||
|
*/
|
||||||
|
public function __toString()
|
||||||
|
{
|
||||||
|
$headers = array();
|
||||||
|
foreach ($this->httpHeaders as $name => $value) {
|
||||||
|
$headers[$name] = (array) $value;
|
||||||
|
}
|
||||||
|
|
||||||
|
return
|
||||||
|
sprintf('HTTP/%s %s %s', $this->version, $this->statusCode, $this->statusText)."\r\n".
|
||||||
|
$this->getHttpHeadersAsString($headers)."\r\n".
|
||||||
|
$this->getResponseBody();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the build header line.
|
||||||
|
*
|
||||||
|
* @param string $name The header name
|
||||||
|
* @param string $value The header value
|
||||||
|
*
|
||||||
|
* @return string The built header line
|
||||||
|
*/
|
||||||
|
protected function buildHeader($name, $value)
|
||||||
|
{
|
||||||
|
return sprintf("%s: %s\n", $name, $value);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getStatusCode()
|
||||||
|
{
|
||||||
|
return $this->statusCode;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setStatusCode($statusCode, $text = null)
|
||||||
|
{
|
||||||
|
$this->statusCode = (int) $statusCode;
|
||||||
|
if ($this->isInvalid()) {
|
||||||
|
throw new \InvalidArgumentException(sprintf('The HTTP status code "%s" is not valid.', $statusCode));
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->statusText = false === $text ? '' : (null === $text ? self::$statusTexts[$this->statusCode] : $text);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getStatusText()
|
||||||
|
{
|
||||||
|
return $this->statusText;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getParameters()
|
||||||
|
{
|
||||||
|
return $this->parameters;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setParameters(array $parameters)
|
||||||
|
{
|
||||||
|
$this->parameters = $parameters;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function addParameters(array $parameters)
|
||||||
|
{
|
||||||
|
$this->parameters = array_merge($this->parameters, $parameters);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getParameter($name, $default = null)
|
||||||
|
{
|
||||||
|
return isset($this->parameters[$name]) ? $this->parameters[$name] : $default;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setParameter($name, $value)
|
||||||
|
{
|
||||||
|
$this->parameters[$name] = $value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setHttpHeaders(array $httpHeaders)
|
||||||
|
{
|
||||||
|
$this->httpHeaders = $httpHeaders;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setHttpHeader($name, $value)
|
||||||
|
{
|
||||||
|
$this->httpHeaders[$name] = $value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function addHttpHeaders(array $httpHeaders)
|
||||||
|
{
|
||||||
|
$this->httpHeaders = array_merge($this->httpHeaders, $httpHeaders);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getHttpHeaders()
|
||||||
|
{
|
||||||
|
return $this->httpHeaders;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getHttpHeader($name, $default = null)
|
||||||
|
{
|
||||||
|
return isset($this->httpHeaders[$name]) ? $this->httpHeaders[$name] : $default;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getResponseBody($format = 'json')
|
||||||
|
{
|
||||||
|
switch ($format) {
|
||||||
|
case 'json':
|
||||||
|
return json_encode($this->parameters);
|
||||||
|
case 'xml':
|
||||||
|
// this only works for single-level arrays
|
||||||
|
$xml = new \SimpleXMLElement('<response/>');
|
||||||
|
foreach ($this->parameters as $key => $param) {
|
||||||
|
$xml->addChild($key, $param);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $xml->asXML();
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new \InvalidArgumentException(sprintf('The format %s is not supported', $format));
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public function send($format = 'json')
|
||||||
|
{
|
||||||
|
// headers have already been sent by the developer
|
||||||
|
if (headers_sent()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch ($format) {
|
||||||
|
case 'json':
|
||||||
|
$this->setHttpHeader('Content-Type', 'application/json');
|
||||||
|
break;
|
||||||
|
case 'xml':
|
||||||
|
$this->setHttpHeader('Content-Type', 'text/xml');
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
// status
|
||||||
|
header(sprintf('HTTP/%s %s %s', $this->version, $this->statusCode, $this->statusText));
|
||||||
|
|
||||||
|
foreach ($this->getHttpHeaders() as $name => $header) {
|
||||||
|
header(sprintf('%s: %s', $name, $header));
|
||||||
|
}
|
||||||
|
echo $this->getResponseBody($format);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setError($statusCode, $error, $errorDescription = null, $errorUri = null)
|
||||||
|
{
|
||||||
|
$parameters = array(
|
||||||
|
'error' => $error,
|
||||||
|
'error_description' => $errorDescription,
|
||||||
|
);
|
||||||
|
|
||||||
|
if (!is_null($errorUri)) {
|
||||||
|
if (strlen($errorUri) > 0 && $errorUri[0] == '#') {
|
||||||
|
// we are referencing an oauth bookmark (for brevity)
|
||||||
|
$errorUri = 'http://tools.ietf.org/html/rfc6749' . $errorUri;
|
||||||
|
}
|
||||||
|
$parameters['error_uri'] = $errorUri;
|
||||||
|
}
|
||||||
|
|
||||||
|
$httpHeaders = array(
|
||||||
|
'Cache-Control' => 'no-store'
|
||||||
|
);
|
||||||
|
|
||||||
|
$this->setStatusCode($statusCode);
|
||||||
|
$this->addParameters($parameters);
|
||||||
|
$this->addHttpHeaders($httpHeaders);
|
||||||
|
|
||||||
|
if (!$this->isClientError() && !$this->isServerError()) {
|
||||||
|
throw new \InvalidArgumentException(sprintf('The HTTP status code is not an error ("%s" given).', $statusCode));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setRedirect($statusCode, $url, $state = null, $error = null, $errorDescription = null, $errorUri = null)
|
||||||
|
{
|
||||||
|
if (empty($url)) {
|
||||||
|
throw new \InvalidArgumentException('Cannot redirect to an empty URL.');
|
||||||
|
}
|
||||||
|
|
||||||
|
$parameters = array();
|
||||||
|
|
||||||
|
if (!is_null($state)) {
|
||||||
|
$parameters['state'] = $state;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!is_null($error)) {
|
||||||
|
$this->setError(400, $error, $errorDescription, $errorUri);
|
||||||
|
}
|
||||||
|
$this->setStatusCode($statusCode);
|
||||||
|
$this->addParameters($parameters);
|
||||||
|
|
||||||
|
if (count($this->parameters) > 0) {
|
||||||
|
// add parameters to URL redirection
|
||||||
|
$parts = parse_url($url);
|
||||||
|
$sep = isset($parts['query']) && count($parts['query']) > 0 ? '&' : '?';
|
||||||
|
$url .= $sep . http_build_query($this->parameters);
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->addHttpHeaders(array('Location' => $url));
|
||||||
|
|
||||||
|
if (!$this->isRedirection()) {
|
||||||
|
throw new \InvalidArgumentException(sprintf('The HTTP status code is not a redirect ("%s" given).', $statusCode));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html
|
||||||
|
/**
|
||||||
|
* @return Boolean
|
||||||
|
*
|
||||||
|
* @api
|
||||||
|
*/
|
||||||
|
public function isInvalid()
|
||||||
|
{
|
||||||
|
return $this->statusCode < 100 || $this->statusCode >= 600;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return Boolean
|
||||||
|
*
|
||||||
|
* @api
|
||||||
|
*/
|
||||||
|
public function isInformational()
|
||||||
|
{
|
||||||
|
return $this->statusCode >= 100 && $this->statusCode < 200;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return Boolean
|
||||||
|
*
|
||||||
|
* @api
|
||||||
|
*/
|
||||||
|
public function isSuccessful()
|
||||||
|
{
|
||||||
|
return $this->statusCode >= 200 && $this->statusCode < 300;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return Boolean
|
||||||
|
*
|
||||||
|
* @api
|
||||||
|
*/
|
||||||
|
public function isRedirection()
|
||||||
|
{
|
||||||
|
return $this->statusCode >= 300 && $this->statusCode < 400;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return Boolean
|
||||||
|
*
|
||||||
|
* @api
|
||||||
|
*/
|
||||||
|
public function isClientError()
|
||||||
|
{
|
||||||
|
return $this->statusCode >= 400 && $this->statusCode < 500;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return Boolean
|
||||||
|
*
|
||||||
|
* @api
|
||||||
|
*/
|
||||||
|
public function isServerError()
|
||||||
|
{
|
||||||
|
return $this->statusCode >= 500 && $this->statusCode < 600;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Functions from Symfony2 HttpFoundation - output pretty header
|
||||||
|
*/
|
||||||
|
private function getHttpHeadersAsString($headers)
|
||||||
|
{
|
||||||
|
if (count($headers) == 0) {
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
|
||||||
|
$max = max(array_map('strlen', array_keys($headers))) + 1;
|
||||||
|
$content = '';
|
||||||
|
ksort($headers);
|
||||||
|
foreach ($headers as $name => $values) {
|
||||||
|
foreach ($values as $value) {
|
||||||
|
$content .= sprintf("%-{$max}s %s\r\n", $this->beautifyHeaderName($name).':', $value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $content;
|
||||||
|
}
|
||||||
|
|
||||||
|
private function beautifyHeaderName($name)
|
||||||
|
{
|
||||||
|
return preg_replace_callback('/\-(.)/', array($this, 'beautifyCallback'), ucfirst($name));
|
||||||
|
}
|
||||||
|
|
||||||
|
private function beautifyCallback($match)
|
||||||
|
{
|
||||||
|
return '-'.strtoupper($match[1]);
|
||||||
|
}
|
||||||
|
}
|
24
vendor/bshaffer/oauth2-server-php/src/OAuth2/ResponseInterface.php
vendored
Normal file
24
vendor/bshaffer/oauth2-server-php/src/OAuth2/ResponseInterface.php
vendored
Normal file
|
@ -0,0 +1,24 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace OAuth2;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Interface which represents an object response. Meant to handle and display the proper OAuth2 Responses
|
||||||
|
* for errors and successes
|
||||||
|
*
|
||||||
|
* @see OAuth2\Response
|
||||||
|
*/
|
||||||
|
interface ResponseInterface
|
||||||
|
{
|
||||||
|
public function addParameters(array $parameters);
|
||||||
|
|
||||||
|
public function addHttpHeaders(array $httpHeaders);
|
||||||
|
|
||||||
|
public function setStatusCode($statusCode);
|
||||||
|
|
||||||
|
public function setError($statusCode, $name, $description = null, $uri = null);
|
||||||
|
|
||||||
|
public function setRedirect($statusCode, $url, $state = null, $error = null, $errorDescription = null, $errorUri = null);
|
||||||
|
|
||||||
|
public function getParameter($name);
|
||||||
|
}
|
194
vendor/bshaffer/oauth2-server-php/src/OAuth2/ResponseType/AccessToken.php
vendored
Normal file
194
vendor/bshaffer/oauth2-server-php/src/OAuth2/ResponseType/AccessToken.php
vendored
Normal file
|
@ -0,0 +1,194 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace OAuth2\ResponseType;
|
||||||
|
|
||||||
|
use OAuth2\Storage\AccessTokenInterface as AccessTokenStorageInterface;
|
||||||
|
use OAuth2\Storage\RefreshTokenInterface;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @author Brent Shaffer <bshafs at gmail dot com>
|
||||||
|
*/
|
||||||
|
class AccessToken implements AccessTokenInterface
|
||||||
|
{
|
||||||
|
protected $tokenStorage;
|
||||||
|
protected $refreshStorage;
|
||||||
|
protected $config;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param OAuth2\Storage\AccessTokenInterface $tokenStorage REQUIRED Storage class for saving access token information
|
||||||
|
* @param OAuth2\Storage\RefreshTokenInterface $refreshStorage OPTIONAL Storage class for saving refresh token information
|
||||||
|
* @param array $config OPTIONAL Configuration options for the server
|
||||||
|
* <code>
|
||||||
|
* $config = array(
|
||||||
|
* 'token_type' => 'bearer', // token type identifier
|
||||||
|
* 'access_lifetime' => 3600, // time before access token expires
|
||||||
|
* 'refresh_token_lifetime' => 1209600, // time before refresh token expires
|
||||||
|
* );
|
||||||
|
* </endcode>
|
||||||
|
*/
|
||||||
|
public function __construct(AccessTokenStorageInterface $tokenStorage, RefreshTokenInterface $refreshStorage = null, array $config = array())
|
||||||
|
{
|
||||||
|
$this->tokenStorage = $tokenStorage;
|
||||||
|
$this->refreshStorage = $refreshStorage;
|
||||||
|
|
||||||
|
$this->config = array_merge(array(
|
||||||
|
'token_type' => 'bearer',
|
||||||
|
'access_lifetime' => 3600,
|
||||||
|
'refresh_token_lifetime' => 1209600,
|
||||||
|
), $config);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getAuthorizeResponse($params, $user_id = null)
|
||||||
|
{
|
||||||
|
// build the URL to redirect to
|
||||||
|
$result = array('query' => array());
|
||||||
|
|
||||||
|
$params += array('scope' => null, 'state' => null);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* a refresh token MUST NOT be included in the fragment
|
||||||
|
*
|
||||||
|
* @see http://tools.ietf.org/html/rfc6749#section-4.2.2
|
||||||
|
*/
|
||||||
|
$includeRefreshToken = false;
|
||||||
|
$result["fragment"] = $this->createAccessToken($params['client_id'], $user_id, $params['scope'], $includeRefreshToken);
|
||||||
|
|
||||||
|
if (isset($params['state'])) {
|
||||||
|
$result["fragment"]["state"] = $params['state'];
|
||||||
|
}
|
||||||
|
|
||||||
|
return array($params['redirect_uri'], $result);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handle the creation of access token, also issue refresh token if supported / desirable.
|
||||||
|
*
|
||||||
|
* @param $client_id client identifier related to the access token.
|
||||||
|
* @param $user_id user ID associated with the access token
|
||||||
|
* @param $scope OPTIONAL scopes to be stored in space-separated string.
|
||||||
|
* @param bool $includeRefreshToken if true, a new refresh_token will be added to the response
|
||||||
|
*
|
||||||
|
* @see http://tools.ietf.org/html/rfc6749#section-5
|
||||||
|
* @ingroup oauth2_section_5
|
||||||
|
*/
|
||||||
|
public function createAccessToken($client_id, $user_id, $scope = null, $includeRefreshToken = true)
|
||||||
|
{
|
||||||
|
$token = array(
|
||||||
|
"access_token" => $this->generateAccessToken(),
|
||||||
|
"expires_in" => $this->config['access_lifetime'],
|
||||||
|
"token_type" => $this->config['token_type'],
|
||||||
|
"scope" => $scope
|
||||||
|
);
|
||||||
|
|
||||||
|
$this->tokenStorage->setAccessToken($token["access_token"], $client_id, $user_id, $this->config['access_lifetime'] ? time() + $this->config['access_lifetime'] : null, $scope);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Issue a refresh token also, if we support them
|
||||||
|
*
|
||||||
|
* Refresh Tokens are considered supported if an instance of OAuth2\Storage\RefreshTokenInterface
|
||||||
|
* is supplied in the constructor
|
||||||
|
*/
|
||||||
|
if ($includeRefreshToken && $this->refreshStorage) {
|
||||||
|
$token["refresh_token"] = $this->generateRefreshToken();
|
||||||
|
$expires = 0;
|
||||||
|
if ($this->config['refresh_token_lifetime'] > 0) {
|
||||||
|
$expires = time() + $this->config['refresh_token_lifetime'];
|
||||||
|
}
|
||||||
|
$this->refreshStorage->setRefreshToken($token['refresh_token'], $client_id, $user_id, $expires, $scope);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $token;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generates an unique access token.
|
||||||
|
*
|
||||||
|
* Implementing classes may want to override this function to implement
|
||||||
|
* other access token generation schemes.
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
* An unique access token.
|
||||||
|
*
|
||||||
|
* @ingroup oauth2_section_4
|
||||||
|
*/
|
||||||
|
protected function generateAccessToken()
|
||||||
|
{
|
||||||
|
if (function_exists('mcrypt_create_iv')) {
|
||||||
|
$randomData = mcrypt_create_iv(20, MCRYPT_DEV_URANDOM);
|
||||||
|
if ($randomData !== false && strlen($randomData) === 20) {
|
||||||
|
return bin2hex($randomData);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (function_exists('openssl_random_pseudo_bytes')) {
|
||||||
|
$randomData = openssl_random_pseudo_bytes(20);
|
||||||
|
if ($randomData !== false && strlen($randomData) === 20) {
|
||||||
|
return bin2hex($randomData);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (@file_exists('/dev/urandom')) { // Get 100 bytes of random data
|
||||||
|
$randomData = file_get_contents('/dev/urandom', false, null, 0, 20);
|
||||||
|
if ($randomData !== false && strlen($randomData) === 20) {
|
||||||
|
return bin2hex($randomData);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Last resort which you probably should just get rid of:
|
||||||
|
$randomData = mt_rand() . mt_rand() . mt_rand() . mt_rand() . microtime(true) . uniqid(mt_rand(), true);
|
||||||
|
|
||||||
|
return substr(hash('sha512', $randomData), 0, 40);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generates an unique refresh token
|
||||||
|
*
|
||||||
|
* Implementing classes may want to override this function to implement
|
||||||
|
* other refresh token generation schemes.
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
* An unique refresh.
|
||||||
|
*
|
||||||
|
* @ingroup oauth2_section_4
|
||||||
|
* @see OAuth2::generateAccessToken()
|
||||||
|
*/
|
||||||
|
protected function generateRefreshToken()
|
||||||
|
{
|
||||||
|
return $this->generateAccessToken(); // let's reuse the same scheme for token generation
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handle the revoking of refresh tokens, and access tokens if supported / desirable
|
||||||
|
* RFC7009 specifies that "If the server is unable to locate the token using
|
||||||
|
* the given hint, it MUST extend its search across all of its supported token types"
|
||||||
|
*
|
||||||
|
* @param $token
|
||||||
|
* @param null $tokenTypeHint
|
||||||
|
* @return boolean
|
||||||
|
*/
|
||||||
|
public function revokeToken($token, $tokenTypeHint = null)
|
||||||
|
{
|
||||||
|
if ($tokenTypeHint == 'refresh_token') {
|
||||||
|
if ($this->refreshStorage && $revoked = $this->refreshStorage->unsetRefreshToken($token)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @TODO remove in v2 */
|
||||||
|
if (!method_exists($this->tokenStorage, 'unsetAccessToken')) {
|
||||||
|
throw new \RuntimeException(
|
||||||
|
sprintf('Token storage %s must implement unsetAccessToken method', get_class($this->tokenStorage)
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
$revoked = $this->tokenStorage->unsetAccessToken($token);
|
||||||
|
|
||||||
|
// if a typehint is supplied and fails, try other storages
|
||||||
|
// @see https://tools.ietf.org/html/rfc7009#section-2.1
|
||||||
|
if (!$revoked && $tokenTypeHint != 'refresh_token') {
|
||||||
|
if ($this->refreshStorage) {
|
||||||
|
$revoked = $this->refreshStorage->unsetRefreshToken($token);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $revoked;
|
||||||
|
}
|
||||||
|
}
|
34
vendor/bshaffer/oauth2-server-php/src/OAuth2/ResponseType/AccessTokenInterface.php
vendored
Normal file
34
vendor/bshaffer/oauth2-server-php/src/OAuth2/ResponseType/AccessTokenInterface.php
vendored
Normal file
|
@ -0,0 +1,34 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace OAuth2\ResponseType;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @author Brent Shaffer <bshafs at gmail dot com>
|
||||||
|
*/
|
||||||
|
interface AccessTokenInterface extends ResponseTypeInterface
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Handle the creation of access token, also issue refresh token if supported / desirable.
|
||||||
|
*
|
||||||
|
* @param $client_id client identifier related to the access token.
|
||||||
|
* @param $user_id user ID associated with the access token
|
||||||
|
* @param $scope OPTONAL scopes to be stored in space-separated string.
|
||||||
|
* @param bool $includeRefreshToken if true, a new refresh_token will be added to the response
|
||||||
|
*
|
||||||
|
* @see http://tools.ietf.org/html/rfc6749#section-5
|
||||||
|
* @ingroup oauth2_section_5
|
||||||
|
*/
|
||||||
|
public function createAccessToken($client_id, $user_id, $scope = null, $includeRefreshToken = true);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handle the revoking of refresh tokens, and access tokens if supported / desirable
|
||||||
|
*
|
||||||
|
* @param $token
|
||||||
|
* @param $tokenTypeHint
|
||||||
|
* @return mixed
|
||||||
|
*
|
||||||
|
* @todo v2.0 include this method in interface. Omitted to maintain BC in v1.x
|
||||||
|
*/
|
||||||
|
//public function revokeToken($token, $tokenTypeHint);
|
||||||
|
}
|
100
vendor/bshaffer/oauth2-server-php/src/OAuth2/ResponseType/AuthorizationCode.php
vendored
Normal file
100
vendor/bshaffer/oauth2-server-php/src/OAuth2/ResponseType/AuthorizationCode.php
vendored
Normal file
|
@ -0,0 +1,100 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace OAuth2\ResponseType;
|
||||||
|
|
||||||
|
use OAuth2\Storage\AuthorizationCodeInterface as AuthorizationCodeStorageInterface;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @author Brent Shaffer <bshafs at gmail dot com>
|
||||||
|
*/
|
||||||
|
class AuthorizationCode implements AuthorizationCodeInterface
|
||||||
|
{
|
||||||
|
protected $storage;
|
||||||
|
protected $config;
|
||||||
|
|
||||||
|
public function __construct(AuthorizationCodeStorageInterface $storage, array $config = array())
|
||||||
|
{
|
||||||
|
$this->storage = $storage;
|
||||||
|
$this->config = array_merge(array(
|
||||||
|
'enforce_redirect' => false,
|
||||||
|
'auth_code_lifetime' => 30,
|
||||||
|
), $config);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getAuthorizeResponse($params, $user_id = null)
|
||||||
|
{
|
||||||
|
// build the URL to redirect to
|
||||||
|
$result = array('query' => array());
|
||||||
|
|
||||||
|
$params += array('scope' => null, 'state' => null);
|
||||||
|
|
||||||
|
$result['query']['code'] = $this->createAuthorizationCode($params['client_id'], $user_id, $params['redirect_uri'], $params['scope']);
|
||||||
|
|
||||||
|
if (isset($params['state'])) {
|
||||||
|
$result['query']['state'] = $params['state'];
|
||||||
|
}
|
||||||
|
|
||||||
|
return array($params['redirect_uri'], $result);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handle the creation of the authorization code.
|
||||||
|
*
|
||||||
|
* @param $client_id
|
||||||
|
* Client identifier related to the authorization code
|
||||||
|
* @param $user_id
|
||||||
|
* User ID associated with the authorization code
|
||||||
|
* @param $redirect_uri
|
||||||
|
* An absolute URI to which the authorization server will redirect the
|
||||||
|
* user-agent to when the end-user authorization step is completed.
|
||||||
|
* @param $scope
|
||||||
|
* (optional) Scopes to be stored in space-separated string.
|
||||||
|
*
|
||||||
|
* @see http://tools.ietf.org/html/rfc6749#section-4
|
||||||
|
* @ingroup oauth2_section_4
|
||||||
|
*/
|
||||||
|
public function createAuthorizationCode($client_id, $user_id, $redirect_uri, $scope = null)
|
||||||
|
{
|
||||||
|
$code = $this->generateAuthorizationCode();
|
||||||
|
$this->storage->setAuthorizationCode($code, $client_id, $user_id, $redirect_uri, time() + $this->config['auth_code_lifetime'], $scope);
|
||||||
|
|
||||||
|
return $code;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return
|
||||||
|
* TRUE if the grant type requires a redirect_uri, FALSE if not
|
||||||
|
*/
|
||||||
|
public function enforceRedirect()
|
||||||
|
{
|
||||||
|
return $this->config['enforce_redirect'];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generates an unique auth code.
|
||||||
|
*
|
||||||
|
* Implementing classes may want to override this function to implement
|
||||||
|
* other auth code generation schemes.
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
* An unique auth code.
|
||||||
|
*
|
||||||
|
* @ingroup oauth2_section_4
|
||||||
|
*/
|
||||||
|
protected function generateAuthorizationCode()
|
||||||
|
{
|
||||||
|
$tokenLen = 40;
|
||||||
|
if (function_exists('mcrypt_create_iv')) {
|
||||||
|
$randomData = mcrypt_create_iv(100, MCRYPT_DEV_URANDOM);
|
||||||
|
} elseif (function_exists('openssl_random_pseudo_bytes')) {
|
||||||
|
$randomData = openssl_random_pseudo_bytes(100);
|
||||||
|
} elseif (@file_exists('/dev/urandom')) { // Get 100 bytes of random data
|
||||||
|
$randomData = file_get_contents('/dev/urandom', false, null, 0, 100) . uniqid(mt_rand(), true);
|
||||||
|
} else {
|
||||||
|
$randomData = mt_rand() . mt_rand() . mt_rand() . mt_rand() . microtime(true) . uniqid(mt_rand(), true);
|
||||||
|
}
|
||||||
|
|
||||||
|
return substr(hash('sha512', $randomData), 0, $tokenLen);
|
||||||
|
}
|
||||||
|
}
|
30
vendor/bshaffer/oauth2-server-php/src/OAuth2/ResponseType/AuthorizationCodeInterface.php
vendored
Normal file
30
vendor/bshaffer/oauth2-server-php/src/OAuth2/ResponseType/AuthorizationCodeInterface.php
vendored
Normal file
|
@ -0,0 +1,30 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace OAuth2\ResponseType;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @author Brent Shaffer <bshafs at gmail dot com>
|
||||||
|
*/
|
||||||
|
interface AuthorizationCodeInterface extends ResponseTypeInterface
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @return
|
||||||
|
* TRUE if the grant type requires a redirect_uri, FALSE if not
|
||||||
|
*/
|
||||||
|
public function enforceRedirect();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handle the creation of the authorization code.
|
||||||
|
*
|
||||||
|
* @param $client_id client identifier related to the authorization code
|
||||||
|
* @param $user_id user id associated with the authorization code
|
||||||
|
* @param $redirect_uri an absolute URI to which the authorization server will redirect the
|
||||||
|
* user-agent to when the end-user authorization step is completed.
|
||||||
|
* @param $scope OPTIONAL scopes to be stored in space-separated string.
|
||||||
|
*
|
||||||
|
* @see http://tools.ietf.org/html/rfc6749#section-4
|
||||||
|
* @ingroup oauth2_section_4
|
||||||
|
*/
|
||||||
|
public function createAuthorizationCode($client_id, $user_id, $redirect_uri, $scope = null);
|
||||||
|
}
|
124
vendor/bshaffer/oauth2-server-php/src/OAuth2/ResponseType/JwtAccessToken.php
vendored
Normal file
124
vendor/bshaffer/oauth2-server-php/src/OAuth2/ResponseType/JwtAccessToken.php
vendored
Normal file
|
@ -0,0 +1,124 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace OAuth2\ResponseType;
|
||||||
|
|
||||||
|
use OAuth2\Encryption\EncryptionInterface;
|
||||||
|
use OAuth2\Encryption\Jwt;
|
||||||
|
use OAuth2\Storage\AccessTokenInterface as AccessTokenStorageInterface;
|
||||||
|
use OAuth2\Storage\RefreshTokenInterface;
|
||||||
|
use OAuth2\Storage\PublicKeyInterface;
|
||||||
|
use OAuth2\Storage\Memory;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @author Brent Shaffer <bshafs at gmail dot com>
|
||||||
|
*/
|
||||||
|
class JwtAccessToken extends AccessToken
|
||||||
|
{
|
||||||
|
protected $publicKeyStorage;
|
||||||
|
protected $encryptionUtil;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param $config
|
||||||
|
* - store_encrypted_token_string (bool true)
|
||||||
|
* whether the entire encrypted string is stored,
|
||||||
|
* or just the token ID is stored
|
||||||
|
*/
|
||||||
|
public function __construct(PublicKeyInterface $publicKeyStorage = null, AccessTokenStorageInterface $tokenStorage = null, RefreshTokenInterface $refreshStorage = null, array $config = array(), EncryptionInterface $encryptionUtil = null)
|
||||||
|
{
|
||||||
|
$this->publicKeyStorage = $publicKeyStorage;
|
||||||
|
$config = array_merge(array(
|
||||||
|
'store_encrypted_token_string' => true,
|
||||||
|
'issuer' => ''
|
||||||
|
), $config);
|
||||||
|
if (is_null($tokenStorage)) {
|
||||||
|
// a pass-thru, so we can call the parent constructor
|
||||||
|
$tokenStorage = new Memory();
|
||||||
|
}
|
||||||
|
if (is_null($encryptionUtil)) {
|
||||||
|
$encryptionUtil = new Jwt();
|
||||||
|
}
|
||||||
|
$this->encryptionUtil = $encryptionUtil;
|
||||||
|
parent::__construct($tokenStorage, $refreshStorage, $config);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handle the creation of access token, also issue refresh token if supported / desirable.
|
||||||
|
*
|
||||||
|
* @param $client_id
|
||||||
|
* Client identifier related to the access token.
|
||||||
|
* @param $user_id
|
||||||
|
* User ID associated with the access token
|
||||||
|
* @param $scope
|
||||||
|
* (optional) Scopes to be stored in space-separated string.
|
||||||
|
* @param bool $includeRefreshToken
|
||||||
|
* If true, a new refresh_token will be added to the response
|
||||||
|
*
|
||||||
|
* @see http://tools.ietf.org/html/rfc6749#section-5
|
||||||
|
* @ingroup oauth2_section_5
|
||||||
|
*/
|
||||||
|
public function createAccessToken($client_id, $user_id, $scope = null, $includeRefreshToken = true)
|
||||||
|
{
|
||||||
|
// token to encrypt
|
||||||
|
$expires = time() + $this->config['access_lifetime'];
|
||||||
|
$id = $this->generateAccessToken();
|
||||||
|
$jwtAccessToken = array(
|
||||||
|
'id' => $id, // for BC (see #591)
|
||||||
|
'jti' => $id,
|
||||||
|
'iss' => $this->config['issuer'],
|
||||||
|
'aud' => $client_id,
|
||||||
|
'sub' => $user_id,
|
||||||
|
'exp' => $expires,
|
||||||
|
'iat' => time(),
|
||||||
|
'token_type' => $this->config['token_type'],
|
||||||
|
'scope' => $scope
|
||||||
|
);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Encode the token data into a single access_token string
|
||||||
|
*/
|
||||||
|
$access_token = $this->encodeToken($jwtAccessToken, $client_id);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Save the token to a secondary storage. This is implemented on the
|
||||||
|
* OAuth2\Storage\JwtAccessToken side, and will not actually store anything,
|
||||||
|
* if no secondary storage has been supplied
|
||||||
|
*/
|
||||||
|
$token_to_store = $this->config['store_encrypted_token_string'] ? $access_token : $jwtAccessToken['id'];
|
||||||
|
$this->tokenStorage->setAccessToken($token_to_store, $client_id, $user_id, $this->config['access_lifetime'] ? time() + $this->config['access_lifetime'] : null, $scope);
|
||||||
|
|
||||||
|
// token to return to the client
|
||||||
|
$token = array(
|
||||||
|
'access_token' => $access_token,
|
||||||
|
'expires_in' => $this->config['access_lifetime'],
|
||||||
|
'token_type' => $this->config['token_type'],
|
||||||
|
'scope' => $scope
|
||||||
|
);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Issue a refresh token also, if we support them
|
||||||
|
*
|
||||||
|
* Refresh Tokens are considered supported if an instance of OAuth2\Storage\RefreshTokenInterface
|
||||||
|
* is supplied in the constructor
|
||||||
|
*/
|
||||||
|
if ($includeRefreshToken && $this->refreshStorage) {
|
||||||
|
$refresh_token = $this->generateRefreshToken();
|
||||||
|
$expires = 0;
|
||||||
|
if ($this->config['refresh_token_lifetime'] > 0) {
|
||||||
|
$expires = time() + $this->config['refresh_token_lifetime'];
|
||||||
|
}
|
||||||
|
$this->refreshStorage->setRefreshToken($refresh_token, $client_id, $user_id, $expires, $scope);
|
||||||
|
$token['refresh_token'] = $refresh_token;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $token;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function encodeToken(array $token, $client_id = null)
|
||||||
|
{
|
||||||
|
$private_key = $this->publicKeyStorage->getPrivateKey($client_id);
|
||||||
|
$algorithm = $this->publicKeyStorage->getEncryptionAlgorithm($client_id);
|
||||||
|
|
||||||
|
return $this->encryptionUtil->encode($token, $private_key, $algorithm);
|
||||||
|
}
|
||||||
|
}
|
8
vendor/bshaffer/oauth2-server-php/src/OAuth2/ResponseType/ResponseTypeInterface.php
vendored
Normal file
8
vendor/bshaffer/oauth2-server-php/src/OAuth2/ResponseType/ResponseTypeInterface.php
vendored
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace OAuth2\ResponseType;
|
||||||
|
|
||||||
|
interface ResponseTypeInterface
|
||||||
|
{
|
||||||
|
public function getAuthorizeResponse($params, $user_id = null);
|
||||||
|
}
|
103
vendor/bshaffer/oauth2-server-php/src/OAuth2/Scope.php
vendored
Normal file
103
vendor/bshaffer/oauth2-server-php/src/OAuth2/Scope.php
vendored
Normal file
|
@ -0,0 +1,103 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace OAuth2;
|
||||||
|
|
||||||
|
use OAuth2\Storage\Memory;
|
||||||
|
use OAuth2\Storage\ScopeInterface as ScopeStorageInterface;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @see OAuth2\ScopeInterface
|
||||||
|
*/
|
||||||
|
class Scope implements ScopeInterface
|
||||||
|
{
|
||||||
|
protected $storage;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param mixed @storage
|
||||||
|
* Either an array of supported scopes, or an instance of OAuth2\Storage\ScopeInterface
|
||||||
|
*/
|
||||||
|
public function __construct($storage = null)
|
||||||
|
{
|
||||||
|
if (is_null($storage) || is_array($storage)) {
|
||||||
|
$storage = new Memory((array) $storage);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!$storage instanceof ScopeStorageInterface) {
|
||||||
|
throw new \InvalidArgumentException("Argument 1 to OAuth2\Scope must be null, an array, or instance of OAuth2\Storage\ScopeInterface");
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->storage = $storage;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if everything in required scope is contained in available scope.
|
||||||
|
*
|
||||||
|
* @param $required_scope
|
||||||
|
* A space-separated string of scopes.
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
* TRUE if everything in required scope is contained in available scope,
|
||||||
|
* and FALSE if it isn't.
|
||||||
|
*
|
||||||
|
* @see http://tools.ietf.org/html/rfc6749#section-7
|
||||||
|
*
|
||||||
|
* @ingroup oauth2_section_7
|
||||||
|
*/
|
||||||
|
public function checkScope($required_scope, $available_scope)
|
||||||
|
{
|
||||||
|
$required_scope = explode(' ', trim($required_scope));
|
||||||
|
$available_scope = explode(' ', trim($available_scope));
|
||||||
|
|
||||||
|
return (count(array_diff($required_scope, $available_scope)) == 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if the provided scope exists in storage.
|
||||||
|
*
|
||||||
|
* @param $scope
|
||||||
|
* A space-separated string of scopes.
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
* TRUE if it exists, FALSE otherwise.
|
||||||
|
*/
|
||||||
|
public function scopeExists($scope)
|
||||||
|
{
|
||||||
|
// Check reserved scopes first.
|
||||||
|
$scope = explode(' ', trim($scope));
|
||||||
|
$reservedScope = $this->getReservedScopes();
|
||||||
|
$nonReservedScopes = array_diff($scope, $reservedScope);
|
||||||
|
if (count($nonReservedScopes) == 0) {
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
// Check the storage for non-reserved scopes.
|
||||||
|
$nonReservedScopes = implode(' ', $nonReservedScopes);
|
||||||
|
|
||||||
|
return $this->storage->scopeExists($nonReservedScopes);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getScopeFromRequest(RequestInterface $request)
|
||||||
|
{
|
||||||
|
// "scope" is valid if passed in either POST or QUERY
|
||||||
|
return $request->request('scope', $request->query('scope'));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getDefaultScope($client_id = null)
|
||||||
|
{
|
||||||
|
return $this->storage->getDefaultScope($client_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get reserved scopes needed by the server.
|
||||||
|
*
|
||||||
|
* In case OpenID Connect is used, these scopes must include:
|
||||||
|
* 'openid', offline_access'.
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
* An array of reserved scopes.
|
||||||
|
*/
|
||||||
|
public function getReservedScopes()
|
||||||
|
{
|
||||||
|
return array('openid', 'offline_access');
|
||||||
|
}
|
||||||
|
}
|
40
vendor/bshaffer/oauth2-server-php/src/OAuth2/ScopeInterface.php
vendored
Normal file
40
vendor/bshaffer/oauth2-server-php/src/OAuth2/ScopeInterface.php
vendored
Normal file
|
@ -0,0 +1,40 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace OAuth2;
|
||||||
|
|
||||||
|
use OAuth2\Storage\ScopeInterface as ScopeStorageInterface;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class to handle scope implementation logic
|
||||||
|
*
|
||||||
|
* @see OAuth2\Storage\ScopeInterface
|
||||||
|
*/
|
||||||
|
interface ScopeInterface extends ScopeStorageInterface
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Check if everything in required scope is contained in available scope.
|
||||||
|
*
|
||||||
|
* @param $required_scope
|
||||||
|
* A space-separated string of scopes.
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
* TRUE if everything in required scope is contained in available scope,
|
||||||
|
* and FALSE if it isn't.
|
||||||
|
*
|
||||||
|
* @see http://tools.ietf.org/html/rfc6749#section-7
|
||||||
|
*
|
||||||
|
* @ingroup oauth2_section_7
|
||||||
|
*/
|
||||||
|
public function checkScope($required_scope, $available_scope);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return scope info from request
|
||||||
|
*
|
||||||
|
* @param OAuth2\RequestInterface
|
||||||
|
* Request object to check
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
* string representation of requested scope
|
||||||
|
*/
|
||||||
|
public function getScopeFromRequest(RequestInterface $request);
|
||||||
|
}
|
832
vendor/bshaffer/oauth2-server-php/src/OAuth2/Server.php
vendored
Normal file
832
vendor/bshaffer/oauth2-server-php/src/OAuth2/Server.php
vendored
Normal file
|
@ -0,0 +1,832 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace OAuth2;
|
||||||
|
|
||||||
|
use OAuth2\Controller\ResourceControllerInterface;
|
||||||
|
use OAuth2\Controller\ResourceController;
|
||||||
|
use OAuth2\OpenID\Controller\UserInfoControllerInterface;
|
||||||
|
use OAuth2\OpenID\Controller\UserInfoController;
|
||||||
|
use OAuth2\OpenID\Controller\AuthorizeController as OpenIDAuthorizeController;
|
||||||
|
use OAuth2\OpenID\ResponseType\AuthorizationCode as OpenIDAuthorizationCodeResponseType;
|
||||||
|
use OAuth2\OpenID\Storage\AuthorizationCodeInterface as OpenIDAuthorizationCodeInterface;
|
||||||
|
use OAuth2\OpenID\GrantType\AuthorizationCode as OpenIDAuthorizationCodeGrantType;
|
||||||
|
use OAuth2\Controller\AuthorizeControllerInterface;
|
||||||
|
use OAuth2\Controller\AuthorizeController;
|
||||||
|
use OAuth2\Controller\TokenControllerInterface;
|
||||||
|
use OAuth2\Controller\TokenController;
|
||||||
|
use OAuth2\ClientAssertionType\ClientAssertionTypeInterface;
|
||||||
|
use OAuth2\ClientAssertionType\HttpBasic;
|
||||||
|
use OAuth2\ResponseType\ResponseTypeInterface;
|
||||||
|
use OAuth2\ResponseType\AuthorizationCode as AuthorizationCodeResponseType;
|
||||||
|
use OAuth2\ResponseType\AccessToken;
|
||||||
|
use OAuth2\ResponseType\JwtAccessToken;
|
||||||
|
use OAuth2\OpenID\ResponseType\CodeIdToken;
|
||||||
|
use OAuth2\OpenID\ResponseType\IdToken;
|
||||||
|
use OAuth2\OpenID\ResponseType\IdTokenToken;
|
||||||
|
use OAuth2\TokenType\TokenTypeInterface;
|
||||||
|
use OAuth2\TokenType\Bearer;
|
||||||
|
use OAuth2\GrantType\GrantTypeInterface;
|
||||||
|
use OAuth2\GrantType\UserCredentials;
|
||||||
|
use OAuth2\GrantType\ClientCredentials;
|
||||||
|
use OAuth2\GrantType\RefreshToken;
|
||||||
|
use OAuth2\GrantType\AuthorizationCode;
|
||||||
|
use OAuth2\Storage\JwtAccessToken as JwtAccessTokenStorage;
|
||||||
|
use OAuth2\Storage\JwtAccessTokenInterface;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Server class for OAuth2
|
||||||
|
* This class serves as a convience class which wraps the other Controller classes
|
||||||
|
*
|
||||||
|
* @see OAuth2\Controller\ResourceController
|
||||||
|
* @see OAuth2\Controller\AuthorizeController
|
||||||
|
* @see OAuth2\Controller\TokenController
|
||||||
|
*/
|
||||||
|
class Server implements ResourceControllerInterface,
|
||||||
|
AuthorizeControllerInterface,
|
||||||
|
TokenControllerInterface,
|
||||||
|
UserInfoControllerInterface
|
||||||
|
{
|
||||||
|
// misc properties
|
||||||
|
protected $response;
|
||||||
|
protected $config;
|
||||||
|
protected $storages;
|
||||||
|
|
||||||
|
// servers
|
||||||
|
protected $authorizeController;
|
||||||
|
protected $tokenController;
|
||||||
|
protected $resourceController;
|
||||||
|
protected $userInfoController;
|
||||||
|
|
||||||
|
// config classes
|
||||||
|
protected $grantTypes;
|
||||||
|
protected $responseTypes;
|
||||||
|
protected $tokenType;
|
||||||
|
protected $scopeUtil;
|
||||||
|
protected $clientAssertionType;
|
||||||
|
|
||||||
|
protected $storageMap = array(
|
||||||
|
'access_token' => 'OAuth2\Storage\AccessTokenInterface',
|
||||||
|
'authorization_code' => 'OAuth2\Storage\AuthorizationCodeInterface',
|
||||||
|
'client_credentials' => 'OAuth2\Storage\ClientCredentialsInterface',
|
||||||
|
'client' => 'OAuth2\Storage\ClientInterface',
|
||||||
|
'refresh_token' => 'OAuth2\Storage\RefreshTokenInterface',
|
||||||
|
'user_credentials' => 'OAuth2\Storage\UserCredentialsInterface',
|
||||||
|
'user_claims' => 'OAuth2\OpenID\Storage\UserClaimsInterface',
|
||||||
|
'public_key' => 'OAuth2\Storage\PublicKeyInterface',
|
||||||
|
'jwt_bearer' => 'OAuth2\Storage\JWTBearerInterface',
|
||||||
|
'scope' => 'OAuth2\Storage\ScopeInterface',
|
||||||
|
);
|
||||||
|
|
||||||
|
protected $responseTypeMap = array(
|
||||||
|
'token' => 'OAuth2\ResponseType\AccessTokenInterface',
|
||||||
|
'code' => 'OAuth2\ResponseType\AuthorizationCodeInterface',
|
||||||
|
'id_token' => 'OAuth2\OpenID\ResponseType\IdTokenInterface',
|
||||||
|
'id_token token' => 'OAuth2\OpenID\ResponseType\IdTokenTokenInterface',
|
||||||
|
'code id_token' => 'OAuth2\OpenID\ResponseType\CodeIdTokenInterface',
|
||||||
|
);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param mixed $storage (array or OAuth2\Storage) - single object or array of objects implementing the
|
||||||
|
* required storage types (ClientCredentialsInterface and AccessTokenInterface as a minimum)
|
||||||
|
* @param array $config specify a different token lifetime, token header name, etc
|
||||||
|
* @param array $grantTypes An array of OAuth2\GrantType\GrantTypeInterface to use for granting access tokens
|
||||||
|
* @param array $responseTypes Response types to use. array keys should be "code" and and "token" for
|
||||||
|
* Access Token and Authorization Code response types
|
||||||
|
* @param OAuth2\TokenType\TokenTypeInterface $tokenType The token type object to use. Valid token types are "bearer" and "mac"
|
||||||
|
* @param OAuth2\ScopeInterface $scopeUtil The scope utility class to use to validate scope
|
||||||
|
* @param OAuth2\ClientAssertionType\ClientAssertionTypeInterface $clientAssertionType The method in which to verify the client identity. Default is HttpBasic
|
||||||
|
*
|
||||||
|
* @ingroup oauth2_section_7
|
||||||
|
*/
|
||||||
|
public function __construct($storage = array(), array $config = array(), array $grantTypes = array(), array $responseTypes = array(), TokenTypeInterface $tokenType = null, ScopeInterface $scopeUtil = null, ClientAssertionTypeInterface $clientAssertionType = null)
|
||||||
|
{
|
||||||
|
$storage = is_array($storage) ? $storage : array($storage);
|
||||||
|
$this->storages = array();
|
||||||
|
foreach ($storage as $key => $service) {
|
||||||
|
$this->addStorage($service, $key);
|
||||||
|
}
|
||||||
|
|
||||||
|
// merge all config values. These get passed to our controller objects
|
||||||
|
$this->config = array_merge(array(
|
||||||
|
'use_jwt_access_tokens' => false,
|
||||||
|
'store_encrypted_token_string' => true,
|
||||||
|
'use_openid_connect' => false,
|
||||||
|
'id_lifetime' => 3600,
|
||||||
|
'access_lifetime' => 3600,
|
||||||
|
'www_realm' => 'Service',
|
||||||
|
'token_param_name' => 'access_token',
|
||||||
|
'token_bearer_header_name' => 'Bearer',
|
||||||
|
'enforce_state' => true,
|
||||||
|
'require_exact_redirect_uri' => true,
|
||||||
|
'allow_implicit' => false,
|
||||||
|
'allow_credentials_in_request_body' => true,
|
||||||
|
'allow_public_clients' => true,
|
||||||
|
'always_issue_new_refresh_token' => false,
|
||||||
|
'unset_refresh_token_after_use' => true,
|
||||||
|
), $config);
|
||||||
|
|
||||||
|
foreach ($grantTypes as $key => $grantType) {
|
||||||
|
$this->addGrantType($grantType, $key);
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach ($responseTypes as $key => $responseType) {
|
||||||
|
$this->addResponseType($responseType, $key);
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->tokenType = $tokenType;
|
||||||
|
$this->scopeUtil = $scopeUtil;
|
||||||
|
$this->clientAssertionType = $clientAssertionType;
|
||||||
|
|
||||||
|
if ($this->config['use_openid_connect']) {
|
||||||
|
$this->validateOpenIdConnect();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getAuthorizeController()
|
||||||
|
{
|
||||||
|
if (is_null($this->authorizeController)) {
|
||||||
|
$this->authorizeController = $this->createDefaultAuthorizeController();
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this->authorizeController;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getTokenController()
|
||||||
|
{
|
||||||
|
if (is_null($this->tokenController)) {
|
||||||
|
$this->tokenController = $this->createDefaultTokenController();
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this->tokenController;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getResourceController()
|
||||||
|
{
|
||||||
|
if (is_null($this->resourceController)) {
|
||||||
|
$this->resourceController = $this->createDefaultResourceController();
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this->resourceController;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getUserInfoController()
|
||||||
|
{
|
||||||
|
if (is_null($this->userInfoController)) {
|
||||||
|
$this->userInfoController = $this->createDefaultUserInfoController();
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this->userInfoController;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* every getter deserves a setter
|
||||||
|
*/
|
||||||
|
public function setAuthorizeController(AuthorizeControllerInterface $authorizeController)
|
||||||
|
{
|
||||||
|
$this->authorizeController = $authorizeController;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* every getter deserves a setter
|
||||||
|
*/
|
||||||
|
public function setTokenController(TokenControllerInterface $tokenController)
|
||||||
|
{
|
||||||
|
$this->tokenController = $tokenController;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* every getter deserves a setter
|
||||||
|
*/
|
||||||
|
public function setResourceController(ResourceControllerInterface $resourceController)
|
||||||
|
{
|
||||||
|
$this->resourceController = $resourceController;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* every getter deserves a setter
|
||||||
|
*/
|
||||||
|
public function setUserInfoController(UserInfoControllerInterface $userInfoController)
|
||||||
|
{
|
||||||
|
$this->userInfoController = $userInfoController;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return claims about the authenticated end-user.
|
||||||
|
* This would be called from the "/UserInfo" endpoint as defined in the spec.
|
||||||
|
*
|
||||||
|
* @param $request - OAuth2\RequestInterface
|
||||||
|
* Request object to grant access token
|
||||||
|
*
|
||||||
|
* @param $response - OAuth2\ResponseInterface
|
||||||
|
* Response object containing error messages (failure) or user claims (success)
|
||||||
|
*
|
||||||
|
* @throws InvalidArgumentException
|
||||||
|
* @throws LogicException
|
||||||
|
*
|
||||||
|
* @see http://openid.net/specs/openid-connect-core-1_0.html#UserInfo
|
||||||
|
*/
|
||||||
|
public function handleUserInfoRequest(RequestInterface $request, ResponseInterface $response = null)
|
||||||
|
{
|
||||||
|
$this->response = is_null($response) ? new Response() : $response;
|
||||||
|
$this->getUserInfoController()->handleUserInfoRequest($request, $this->response);
|
||||||
|
|
||||||
|
return $this->response;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Grant or deny a requested access token.
|
||||||
|
* This would be called from the "/token" endpoint as defined in the spec.
|
||||||
|
* Obviously, you can call your endpoint whatever you want.
|
||||||
|
*
|
||||||
|
* @param $request - OAuth2\RequestInterface
|
||||||
|
* Request object to grant access token
|
||||||
|
*
|
||||||
|
* @param $response - OAuth2\ResponseInterface
|
||||||
|
* Response object containing error messages (failure) or access token (success)
|
||||||
|
*
|
||||||
|
* @throws InvalidArgumentException
|
||||||
|
* @throws LogicException
|
||||||
|
*
|
||||||
|
* @see http://tools.ietf.org/html/rfc6749#section-4
|
||||||
|
* @see http://tools.ietf.org/html/rfc6749#section-10.6
|
||||||
|
* @see http://tools.ietf.org/html/rfc6749#section-4.1.3
|
||||||
|
*
|
||||||
|
* @ingroup oauth2_section_4
|
||||||
|
*/
|
||||||
|
public function handleTokenRequest(RequestInterface $request, ResponseInterface $response = null)
|
||||||
|
{
|
||||||
|
$this->response = is_null($response) ? new Response() : $response;
|
||||||
|
$this->getTokenController()->handleTokenRequest($request, $this->response);
|
||||||
|
|
||||||
|
return $this->response;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function grantAccessToken(RequestInterface $request, ResponseInterface $response = null)
|
||||||
|
{
|
||||||
|
$this->response = is_null($response) ? new Response() : $response;
|
||||||
|
$value = $this->getTokenController()->grantAccessToken($request, $this->response);
|
||||||
|
|
||||||
|
return $value;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handle a revoke token request
|
||||||
|
* This would be called from the "/revoke" endpoint as defined in the draft Token Revocation spec
|
||||||
|
*
|
||||||
|
* @see https://tools.ietf.org/html/rfc7009#section-2
|
||||||
|
*
|
||||||
|
* @param RequestInterface $request
|
||||||
|
* @param ResponseInterface $response
|
||||||
|
* @return Response|ResponseInterface
|
||||||
|
*/
|
||||||
|
public function handleRevokeRequest(RequestInterface $request, ResponseInterface $response = null)
|
||||||
|
{
|
||||||
|
$this->response = is_null($response) ? new Response() : $response;
|
||||||
|
$this->getTokenController()->handleRevokeRequest($request, $this->response);
|
||||||
|
|
||||||
|
return $this->response;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Redirect the user appropriately after approval.
|
||||||
|
*
|
||||||
|
* After the user has approved or denied the resource request the
|
||||||
|
* authorization server should call this function to redirect the user
|
||||||
|
* appropriately.
|
||||||
|
*
|
||||||
|
* @param $request
|
||||||
|
* The request should have the follow parameters set in the querystring:
|
||||||
|
* - response_type: The requested response: an access token, an
|
||||||
|
* authorization code, or both.
|
||||||
|
* - client_id: The client identifier as described in Section 2.
|
||||||
|
* - redirect_uri: An absolute URI to which the authorization server
|
||||||
|
* will redirect the user-agent to when the end-user authorization
|
||||||
|
* step is completed.
|
||||||
|
* - scope: (optional) The scope of the resource request expressed as a
|
||||||
|
* list of space-delimited strings.
|
||||||
|
* - state: (optional) An opaque value used by the client to maintain
|
||||||
|
* state between the request and callback.
|
||||||
|
* @param $is_authorized
|
||||||
|
* TRUE or FALSE depending on whether the user authorized the access.
|
||||||
|
* @param $user_id
|
||||||
|
* Identifier of user who authorized the client
|
||||||
|
*
|
||||||
|
* @see http://tools.ietf.org/html/rfc6749#section-4
|
||||||
|
*
|
||||||
|
* @ingroup oauth2_section_4
|
||||||
|
*/
|
||||||
|
public function handleAuthorizeRequest(RequestInterface $request, ResponseInterface $response, $is_authorized, $user_id = null)
|
||||||
|
{
|
||||||
|
$this->response = $response;
|
||||||
|
$this->getAuthorizeController()->handleAuthorizeRequest($request, $this->response, $is_authorized, $user_id);
|
||||||
|
|
||||||
|
return $this->response;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Pull the authorization request data out of the HTTP request.
|
||||||
|
* - The redirect_uri is OPTIONAL as per draft 20. But your implementation can enforce it
|
||||||
|
* by setting $config['enforce_redirect'] to true.
|
||||||
|
* - The state is OPTIONAL but recommended to enforce CSRF. Draft 21 states, however, that
|
||||||
|
* CSRF protection is MANDATORY. You can enforce this by setting the $config['enforce_state'] to true.
|
||||||
|
*
|
||||||
|
* The draft specifies that the parameters should be retrieved from GET, override the Response
|
||||||
|
* object to change this
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
* The authorization parameters so the authorization server can prompt
|
||||||
|
* the user for approval if valid.
|
||||||
|
*
|
||||||
|
* @see http://tools.ietf.org/html/rfc6749#section-4.1.1
|
||||||
|
* @see http://tools.ietf.org/html/rfc6749#section-10.12
|
||||||
|
*
|
||||||
|
* @ingroup oauth2_section_3
|
||||||
|
*/
|
||||||
|
public function validateAuthorizeRequest(RequestInterface $request, ResponseInterface $response = null)
|
||||||
|
{
|
||||||
|
$this->response = is_null($response) ? new Response() : $response;
|
||||||
|
$value = $this->getAuthorizeController()->validateAuthorizeRequest($request, $this->response);
|
||||||
|
|
||||||
|
return $value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function verifyResourceRequest(RequestInterface $request, ResponseInterface $response = null, $scope = null)
|
||||||
|
{
|
||||||
|
$this->response = is_null($response) ? new Response() : $response;
|
||||||
|
$value = $this->getResourceController()->verifyResourceRequest($request, $this->response, $scope);
|
||||||
|
|
||||||
|
return $value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getAccessTokenData(RequestInterface $request, ResponseInterface $response = null)
|
||||||
|
{
|
||||||
|
$this->response = is_null($response) ? new Response() : $response;
|
||||||
|
$value = $this->getResourceController()->getAccessTokenData($request, $this->response);
|
||||||
|
|
||||||
|
return $value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function addGrantType(GrantTypeInterface $grantType, $identifier = null)
|
||||||
|
{
|
||||||
|
if (!is_string($identifier)) {
|
||||||
|
$identifier = $grantType->getQuerystringIdentifier();
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->grantTypes[$identifier] = $grantType;
|
||||||
|
|
||||||
|
// persist added grant type down to TokenController
|
||||||
|
if (!is_null($this->tokenController)) {
|
||||||
|
$this->getTokenController()->addGrantType($grantType, $identifier);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set a storage object for the server
|
||||||
|
*
|
||||||
|
* @param $storage
|
||||||
|
* An object implementing one of the Storage interfaces
|
||||||
|
* @param $key
|
||||||
|
* If null, the storage is set to the key of each storage interface it implements
|
||||||
|
*
|
||||||
|
* @see storageMap
|
||||||
|
*/
|
||||||
|
public function addStorage($storage, $key = null)
|
||||||
|
{
|
||||||
|
// if explicitly set to a valid key, do not "magically" set below
|
||||||
|
if (isset($this->storageMap[$key])) {
|
||||||
|
if (!is_null($storage) && !$storage instanceof $this->storageMap[$key]) {
|
||||||
|
throw new \InvalidArgumentException(sprintf('storage of type "%s" must implement interface "%s"', $key, $this->storageMap[$key]));
|
||||||
|
}
|
||||||
|
$this->storages[$key] = $storage;
|
||||||
|
|
||||||
|
// special logic to handle "client" and "client_credentials" strangeness
|
||||||
|
if ($key === 'client' && !isset($this->storages['client_credentials'])) {
|
||||||
|
if ($storage instanceof \OAuth2\Storage\ClientCredentialsInterface) {
|
||||||
|
$this->storages['client_credentials'] = $storage;
|
||||||
|
}
|
||||||
|
} elseif ($key === 'client_credentials' && !isset($this->storages['client'])) {
|
||||||
|
if ($storage instanceof \OAuth2\Storage\ClientInterface) {
|
||||||
|
$this->storages['client'] = $storage;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} elseif (!is_null($key) && !is_numeric($key)) {
|
||||||
|
throw new \InvalidArgumentException(sprintf('unknown storage key "%s", must be one of [%s]', $key, implode(', ', array_keys($this->storageMap))));
|
||||||
|
} else {
|
||||||
|
$set = false;
|
||||||
|
foreach ($this->storageMap as $type => $interface) {
|
||||||
|
if ($storage instanceof $interface) {
|
||||||
|
$this->storages[$type] = $storage;
|
||||||
|
$set = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!$set) {
|
||||||
|
throw new \InvalidArgumentException(sprintf('storage of class "%s" must implement one of [%s]', get_class($storage), implode(', ', $this->storageMap)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public function addResponseType(ResponseTypeInterface $responseType, $key = null)
|
||||||
|
{
|
||||||
|
$key = $this->normalizeResponseType($key);
|
||||||
|
|
||||||
|
if (isset($this->responseTypeMap[$key])) {
|
||||||
|
if (!$responseType instanceof $this->responseTypeMap[$key]) {
|
||||||
|
throw new \InvalidArgumentException(sprintf('responseType of type "%s" must implement interface "%s"', $key, $this->responseTypeMap[$key]));
|
||||||
|
}
|
||||||
|
$this->responseTypes[$key] = $responseType;
|
||||||
|
} elseif (!is_null($key) && !is_numeric($key)) {
|
||||||
|
throw new \InvalidArgumentException(sprintf('unknown responseType key "%s", must be one of [%s]', $key, implode(', ', array_keys($this->responseTypeMap))));
|
||||||
|
} else {
|
||||||
|
$set = false;
|
||||||
|
foreach ($this->responseTypeMap as $type => $interface) {
|
||||||
|
if ($responseType instanceof $interface) {
|
||||||
|
$this->responseTypes[$type] = $responseType;
|
||||||
|
$set = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!$set) {
|
||||||
|
throw new \InvalidArgumentException(sprintf('Unknown response type %s. Please implement one of [%s]', get_class($responseType), implode(', ', $this->responseTypeMap)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getScopeUtil()
|
||||||
|
{
|
||||||
|
if (!$this->scopeUtil) {
|
||||||
|
$storage = isset($this->storages['scope']) ? $this->storages['scope'] : null;
|
||||||
|
$this->scopeUtil = new Scope($storage);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this->scopeUtil;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* every getter deserves a setter
|
||||||
|
*/
|
||||||
|
public function setScopeUtil($scopeUtil)
|
||||||
|
{
|
||||||
|
$this->scopeUtil = $scopeUtil;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function createDefaultAuthorizeController()
|
||||||
|
{
|
||||||
|
if (!isset($this->storages['client'])) {
|
||||||
|
throw new \LogicException("You must supply a storage object implementing OAuth2\Storage\ClientInterface to use the authorize server");
|
||||||
|
}
|
||||||
|
if (0 == count($this->responseTypes)) {
|
||||||
|
$this->responseTypes = $this->getDefaultResponseTypes();
|
||||||
|
}
|
||||||
|
if ($this->config['use_openid_connect'] && !isset($this->responseTypes['id_token'])) {
|
||||||
|
$this->responseTypes['id_token'] = $this->createDefaultIdTokenResponseType();
|
||||||
|
if ($this->config['allow_implicit']) {
|
||||||
|
$this->responseTypes['id_token token'] = $this->createDefaultIdTokenTokenResponseType();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$config = array_intersect_key($this->config, array_flip(explode(' ', 'allow_implicit enforce_state require_exact_redirect_uri')));
|
||||||
|
|
||||||
|
if ($this->config['use_openid_connect']) {
|
||||||
|
return new OpenIDAuthorizeController($this->storages['client'], $this->responseTypes, $config, $this->getScopeUtil());
|
||||||
|
}
|
||||||
|
|
||||||
|
return new AuthorizeController($this->storages['client'], $this->responseTypes, $config, $this->getScopeUtil());
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function createDefaultTokenController()
|
||||||
|
{
|
||||||
|
if (0 == count($this->grantTypes)) {
|
||||||
|
$this->grantTypes = $this->getDefaultGrantTypes();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (is_null($this->clientAssertionType)) {
|
||||||
|
// see if HttpBasic assertion type is requred. If so, then create it from storage classes.
|
||||||
|
foreach ($this->grantTypes as $grantType) {
|
||||||
|
if (!$grantType instanceof ClientAssertionTypeInterface) {
|
||||||
|
if (!isset($this->storages['client_credentials'])) {
|
||||||
|
throw new \LogicException("You must supply a storage object implementing OAuth2\Storage\ClientCredentialsInterface to use the token server");
|
||||||
|
}
|
||||||
|
$config = array_intersect_key($this->config, array_flip(explode(' ', 'allow_credentials_in_request_body allow_public_clients')));
|
||||||
|
$this->clientAssertionType = new HttpBasic($this->storages['client_credentials'], $config);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!isset($this->storages['client'])) {
|
||||||
|
throw new \LogicException("You must supply a storage object implementing OAuth2\Storage\ClientInterface to use the token server");
|
||||||
|
}
|
||||||
|
|
||||||
|
$accessTokenResponseType = $this->getAccessTokenResponseType();
|
||||||
|
|
||||||
|
return new TokenController($accessTokenResponseType, $this->storages['client'], $this->grantTypes, $this->clientAssertionType, $this->getScopeUtil());
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function createDefaultResourceController()
|
||||||
|
{
|
||||||
|
if ($this->config['use_jwt_access_tokens']) {
|
||||||
|
// overwrites access token storage with crypto token storage if "use_jwt_access_tokens" is set
|
||||||
|
if (!isset($this->storages['access_token']) || !$this->storages['access_token'] instanceof JwtAccessTokenInterface) {
|
||||||
|
$this->storages['access_token'] = $this->createDefaultJwtAccessTokenStorage();
|
||||||
|
}
|
||||||
|
} elseif (!isset($this->storages['access_token'])) {
|
||||||
|
throw new \LogicException("You must supply a storage object implementing OAuth2\Storage\AccessTokenInterface or use JwtAccessTokens to use the resource server");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!$this->tokenType) {
|
||||||
|
$this->tokenType = $this->getDefaultTokenType();
|
||||||
|
}
|
||||||
|
|
||||||
|
$config = array_intersect_key($this->config, array('www_realm' => ''));
|
||||||
|
|
||||||
|
return new ResourceController($this->tokenType, $this->storages['access_token'], $config, $this->getScopeUtil());
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function createDefaultUserInfoController()
|
||||||
|
{
|
||||||
|
if ($this->config['use_jwt_access_tokens']) {
|
||||||
|
// overwrites access token storage with crypto token storage if "use_jwt_access_tokens" is set
|
||||||
|
if (!isset($this->storages['access_token']) || !$this->storages['access_token'] instanceof JwtAccessTokenInterface) {
|
||||||
|
$this->storages['access_token'] = $this->createDefaultJwtAccessTokenStorage();
|
||||||
|
}
|
||||||
|
} elseif (!isset($this->storages['access_token'])) {
|
||||||
|
throw new \LogicException("You must supply a storage object implementing OAuth2\Storage\AccessTokenInterface or use JwtAccessTokens to use the UserInfo server");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!isset($this->storages['user_claims'])) {
|
||||||
|
throw new \LogicException("You must supply a storage object implementing OAuth2\OpenID\Storage\UserClaimsInterface to use the UserInfo server");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!$this->tokenType) {
|
||||||
|
$this->tokenType = $this->getDefaultTokenType();
|
||||||
|
}
|
||||||
|
|
||||||
|
$config = array_intersect_key($this->config, array('www_realm' => ''));
|
||||||
|
|
||||||
|
return new UserInfoController($this->tokenType, $this->storages['access_token'], $this->storages['user_claims'], $config, $this->getScopeUtil());
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function getDefaultTokenType()
|
||||||
|
{
|
||||||
|
$config = array_intersect_key($this->config, array_flip(explode(' ', 'token_param_name token_bearer_header_name')));
|
||||||
|
|
||||||
|
return new Bearer($config);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function getDefaultResponseTypes()
|
||||||
|
{
|
||||||
|
$responseTypes = array();
|
||||||
|
|
||||||
|
if ($this->config['allow_implicit']) {
|
||||||
|
$responseTypes['token'] = $this->getAccessTokenResponseType();
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($this->config['use_openid_connect']) {
|
||||||
|
$responseTypes['id_token'] = $this->getIdTokenResponseType();
|
||||||
|
if ($this->config['allow_implicit']) {
|
||||||
|
$responseTypes['id_token token'] = $this->getIdTokenTokenResponseType();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isset($this->storages['authorization_code'])) {
|
||||||
|
$config = array_intersect_key($this->config, array_flip(explode(' ', 'enforce_redirect auth_code_lifetime')));
|
||||||
|
if ($this->config['use_openid_connect']) {
|
||||||
|
if (!$this->storages['authorization_code'] instanceof OpenIDAuthorizationCodeInterface) {
|
||||||
|
throw new \LogicException("Your authorization_code storage must implement OAuth2\OpenID\Storage\AuthorizationCodeInterface to work when 'use_openid_connect' is true");
|
||||||
|
}
|
||||||
|
$responseTypes['code'] = new OpenIDAuthorizationCodeResponseType($this->storages['authorization_code'], $config);
|
||||||
|
$responseTypes['code id_token'] = new CodeIdToken($responseTypes['code'], $responseTypes['id_token']);
|
||||||
|
} else {
|
||||||
|
$responseTypes['code'] = new AuthorizationCodeResponseType($this->storages['authorization_code'], $config);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (count($responseTypes) == 0) {
|
||||||
|
throw new \LogicException("You must supply an array of response_types in the constructor or implement a OAuth2\Storage\AuthorizationCodeInterface storage object or set 'allow_implicit' to true and implement a OAuth2\Storage\AccessTokenInterface storage object");
|
||||||
|
}
|
||||||
|
|
||||||
|
return $responseTypes;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function getDefaultGrantTypes()
|
||||||
|
{
|
||||||
|
$grantTypes = array();
|
||||||
|
|
||||||
|
if (isset($this->storages['user_credentials'])) {
|
||||||
|
$grantTypes['password'] = new UserCredentials($this->storages['user_credentials']);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isset($this->storages['client_credentials'])) {
|
||||||
|
$config = array_intersect_key($this->config, array('allow_credentials_in_request_body' => ''));
|
||||||
|
$grantTypes['client_credentials'] = new ClientCredentials($this->storages['client_credentials'], $config);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isset($this->storages['refresh_token'])) {
|
||||||
|
$config = array_intersect_key($this->config, array_flip(explode(' ', 'always_issue_new_refresh_token unset_refresh_token_after_use')));
|
||||||
|
$grantTypes['refresh_token'] = new RefreshToken($this->storages['refresh_token'], $config);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isset($this->storages['authorization_code'])) {
|
||||||
|
if ($this->config['use_openid_connect']) {
|
||||||
|
if (!$this->storages['authorization_code'] instanceof OpenIDAuthorizationCodeInterface) {
|
||||||
|
throw new \LogicException("Your authorization_code storage must implement OAuth2\OpenID\Storage\AuthorizationCodeInterface to work when 'use_openid_connect' is true");
|
||||||
|
}
|
||||||
|
$grantTypes['authorization_code'] = new OpenIDAuthorizationCodeGrantType($this->storages['authorization_code']);
|
||||||
|
} else {
|
||||||
|
$grantTypes['authorization_code'] = new AuthorizationCode($this->storages['authorization_code']);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (count($grantTypes) == 0) {
|
||||||
|
throw new \LogicException("Unable to build default grant types - You must supply an array of grant_types in the constructor");
|
||||||
|
}
|
||||||
|
|
||||||
|
return $grantTypes;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function getAccessTokenResponseType()
|
||||||
|
{
|
||||||
|
if (isset($this->responseTypes['token'])) {
|
||||||
|
return $this->responseTypes['token'];
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($this->config['use_jwt_access_tokens']) {
|
||||||
|
return $this->createDefaultJwtAccessTokenResponseType();
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this->createDefaultAccessTokenResponseType();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function getIdTokenResponseType()
|
||||||
|
{
|
||||||
|
if (isset($this->responseTypes['id_token'])) {
|
||||||
|
return $this->responseTypes['id_token'];
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this->createDefaultIdTokenResponseType();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function getIdTokenTokenResponseType()
|
||||||
|
{
|
||||||
|
if (isset($this->responseTypes['id_token token'])) {
|
||||||
|
return $this->responseTypes['id_token token'];
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this->createDefaultIdTokenTokenResponseType();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* For Resource Controller
|
||||||
|
*/
|
||||||
|
protected function createDefaultJwtAccessTokenStorage()
|
||||||
|
{
|
||||||
|
if (!isset($this->storages['public_key'])) {
|
||||||
|
throw new \LogicException("You must supply a storage object implementing OAuth2\Storage\PublicKeyInterface to use crypto tokens");
|
||||||
|
}
|
||||||
|
$tokenStorage = null;
|
||||||
|
if (!empty($this->config['store_encrypted_token_string']) && isset($this->storages['access_token'])) {
|
||||||
|
$tokenStorage = $this->storages['access_token'];
|
||||||
|
}
|
||||||
|
// wrap the access token storage as required.
|
||||||
|
return new JwtAccessTokenStorage($this->storages['public_key'], $tokenStorage);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* For Authorize and Token Controllers
|
||||||
|
*/
|
||||||
|
protected function createDefaultJwtAccessTokenResponseType()
|
||||||
|
{
|
||||||
|
if (!isset($this->storages['public_key'])) {
|
||||||
|
throw new \LogicException("You must supply a storage object implementing OAuth2\Storage\PublicKeyInterface to use crypto tokens");
|
||||||
|
}
|
||||||
|
|
||||||
|
$tokenStorage = null;
|
||||||
|
if (isset($this->storages['access_token'])) {
|
||||||
|
$tokenStorage = $this->storages['access_token'];
|
||||||
|
}
|
||||||
|
|
||||||
|
$refreshStorage = null;
|
||||||
|
if (isset($this->storages['refresh_token'])) {
|
||||||
|
$refreshStorage = $this->storages['refresh_token'];
|
||||||
|
}
|
||||||
|
|
||||||
|
$config = array_intersect_key($this->config, array_flip(explode(' ', 'store_encrypted_token_string issuer access_lifetime refresh_token_lifetime')));
|
||||||
|
|
||||||
|
return new JwtAccessToken($this->storages['public_key'], $tokenStorage, $refreshStorage, $config);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function createDefaultAccessTokenResponseType()
|
||||||
|
{
|
||||||
|
if (!isset($this->storages['access_token'])) {
|
||||||
|
throw new \LogicException("You must supply a response type implementing OAuth2\ResponseType\AccessTokenInterface, or a storage object implementing OAuth2\Storage\AccessTokenInterface to use the token server");
|
||||||
|
}
|
||||||
|
|
||||||
|
$refreshStorage = null;
|
||||||
|
if (isset($this->storages['refresh_token'])) {
|
||||||
|
$refreshStorage = $this->storages['refresh_token'];
|
||||||
|
}
|
||||||
|
|
||||||
|
$config = array_intersect_key($this->config, array_flip(explode(' ', 'access_lifetime refresh_token_lifetime')));
|
||||||
|
$config['token_type'] = $this->tokenType ? $this->tokenType->getTokenType() : $this->getDefaultTokenType()->getTokenType();
|
||||||
|
|
||||||
|
return new AccessToken($this->storages['access_token'], $refreshStorage, $config);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function createDefaultIdTokenResponseType()
|
||||||
|
{
|
||||||
|
if (!isset($this->storages['user_claims'])) {
|
||||||
|
throw new \LogicException("You must supply a storage object implementing OAuth2\OpenID\Storage\UserClaimsInterface to use openid connect");
|
||||||
|
}
|
||||||
|
if (!isset($this->storages['public_key'])) {
|
||||||
|
throw new \LogicException("You must supply a storage object implementing OAuth2\Storage\PublicKeyInterface to use openid connect");
|
||||||
|
}
|
||||||
|
|
||||||
|
$config = array_intersect_key($this->config, array_flip(explode(' ', 'issuer id_lifetime')));
|
||||||
|
|
||||||
|
return new IdToken($this->storages['user_claims'], $this->storages['public_key'], $config);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function createDefaultIdTokenTokenResponseType()
|
||||||
|
{
|
||||||
|
return new IdTokenToken($this->getAccessTokenResponseType(), $this->getIdTokenResponseType());
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function validateOpenIdConnect()
|
||||||
|
{
|
||||||
|
$authCodeGrant = $this->getGrantType('authorization_code');
|
||||||
|
if (!empty($authCodeGrant) && !$authCodeGrant instanceof OpenIDAuthorizationCodeGrantType) {
|
||||||
|
throw new \InvalidArgumentException('You have enabled OpenID Connect, but supplied a grant type that does not support it.');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function normalizeResponseType($name)
|
||||||
|
{
|
||||||
|
// for multiple-valued response types - make them alphabetical
|
||||||
|
if (!empty($name) && false !== strpos($name, ' ')) {
|
||||||
|
$types = explode(' ', $name);
|
||||||
|
sort($types);
|
||||||
|
$name = implode(' ', $types);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getResponse()
|
||||||
|
{
|
||||||
|
return $this->response;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getStorages()
|
||||||
|
{
|
||||||
|
return $this->storages;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getStorage($name)
|
||||||
|
{
|
||||||
|
return isset($this->storages[$name]) ? $this->storages[$name] : null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getGrantTypes()
|
||||||
|
{
|
||||||
|
return $this->grantTypes;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getGrantType($name)
|
||||||
|
{
|
||||||
|
return isset($this->grantTypes[$name]) ? $this->grantTypes[$name] : null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getResponseTypes()
|
||||||
|
{
|
||||||
|
return $this->responseTypes;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getResponseType($name)
|
||||||
|
{
|
||||||
|
// for multiple-valued response types - make them alphabetical
|
||||||
|
$name = $this->normalizeResponseType($name);
|
||||||
|
|
||||||
|
return isset($this->responseTypes[$name]) ? $this->responseTypes[$name] : null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getTokenType()
|
||||||
|
{
|
||||||
|
return $this->tokenType;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getClientAssertionType()
|
||||||
|
{
|
||||||
|
return $this->clientAssertionType;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setConfig($name, $value)
|
||||||
|
{
|
||||||
|
$this->config[$name] = $value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getConfig($name, $default = null)
|
||||||
|
{
|
||||||
|
return isset($this->config[$name]) ? $this->config[$name] : $default;
|
||||||
|
}
|
||||||
|
}
|
63
vendor/bshaffer/oauth2-server-php/src/OAuth2/Storage/AccessTokenInterface.php
vendored
Normal file
63
vendor/bshaffer/oauth2-server-php/src/OAuth2/Storage/AccessTokenInterface.php
vendored
Normal file
|
@ -0,0 +1,63 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace OAuth2\Storage;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Implement this interface to specify where the OAuth2 Server
|
||||||
|
* should get/save access tokens
|
||||||
|
*
|
||||||
|
* @author Brent Shaffer <bshafs at gmail dot com>
|
||||||
|
*/
|
||||||
|
interface AccessTokenInterface
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Look up the supplied oauth_token from storage.
|
||||||
|
*
|
||||||
|
* We need to retrieve access token data as we create and verify tokens.
|
||||||
|
*
|
||||||
|
* @param $oauth_token
|
||||||
|
* oauth_token to be check with.
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
* An associative array as below, and return NULL if the supplied oauth_token
|
||||||
|
* is invalid:
|
||||||
|
* - expires: Stored expiration in unix timestamp.
|
||||||
|
* - client_id: (optional) Stored client identifier.
|
||||||
|
* - user_id: (optional) Stored user identifier.
|
||||||
|
* - scope: (optional) Stored scope values in space-separated string.
|
||||||
|
* - id_token: (optional) Stored id_token (if "use_openid_connect" is true).
|
||||||
|
*
|
||||||
|
* @ingroup oauth2_section_7
|
||||||
|
*/
|
||||||
|
public function getAccessToken($oauth_token);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Store the supplied access token values to storage.
|
||||||
|
*
|
||||||
|
* We need to store access token data as we create and verify tokens.
|
||||||
|
*
|
||||||
|
* @param $oauth_token oauth_token to be stored.
|
||||||
|
* @param $client_id client identifier to be stored.
|
||||||
|
* @param $user_id user identifier to be stored.
|
||||||
|
* @param int $expires expiration to be stored as a Unix timestamp.
|
||||||
|
* @param string $scope OPTIONAL Scopes to be stored in space-separated string.
|
||||||
|
*
|
||||||
|
* @ingroup oauth2_section_4
|
||||||
|
*/
|
||||||
|
public function setAccessToken($oauth_token, $client_id, $user_id, $expires, $scope = null);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Expire an access token.
|
||||||
|
*
|
||||||
|
* This is not explicitly required in the spec, but if defined in a draft RFC for token
|
||||||
|
* revoking (RFC 7009) https://tools.ietf.org/html/rfc7009
|
||||||
|
*
|
||||||
|
* @param $access_token
|
||||||
|
* Access token to be expired.
|
||||||
|
*
|
||||||
|
* @ingroup oauth2_section_6
|
||||||
|
*
|
||||||
|
* @todo v2.0 include this method in interface. Omitted to maintain BC in v1.x
|
||||||
|
*/
|
||||||
|
//public function unsetAccessToken($access_token);
|
||||||
|
}
|
Some files were not shown because too many files have changed in this diff Show more
Reference in a new issue