Improvement for OAuth2 Server. Implicit, Resource Owner Password and Client Credentials were added, and refactoring of oauth2 endpoints

This commit is contained in:
eriknyk
2014-08-20 11:36:20 -04:00
parent dfb0647c80
commit c108ea8678
17 changed files with 1609 additions and 64 deletions

View File

@@ -18,6 +18,8 @@ class Restler extends \Luracast\Restler\Restler
public $responseMultipart = array(); public $responseMultipart = array();
public $inputExecute = ''; public $inputExecute = '';
protected $workspace;
public function __construct($productionMode = false, $refreshCache = false) public function __construct($productionMode = false, $refreshCache = false)
{ {
parent::__construct($productionMode, $refreshCache); parent::__construct($productionMode, $refreshCache);
@@ -127,4 +129,14 @@ class Restler extends \Luracast\Restler\Restler
{ {
$this->message($e); $this->message($e);
} }
public function setWorkspace($workspace)
{
$this->workspace = $workspace;
}
public function getWorkspace()
{
return $this->workspace;
}
} }

View File

@@ -0,0 +1,29 @@
<?php
namespace Maveriks\Pattern\Mvc;
class SmartyView extends View
{
protected $smarty;
public function __construct($tpl = '')
{
parent::__construct($tpl);
require_once PATH_THIRDPARTY . 'smarty/libs/Smarty.class.php'; //
$this->smarty = new \Smarty();
$this->smarty->compile_dir = defined('PATH_SMARTY_C')? PATH_SMARTY_C : sys_get_temp_dir();
$this->smarty->cache_dir = defined('PATH_SMARTY_CACHE')? PATH_SMARTY_CACHE : sys_get_temp_dir();
//$this->smarty->config_dir = PATH_THIRDPARTY . 'smarty/configs';
//$this->smarty->register_function('translate', 'translate');
}
public function assign($name, $value)
{
$this->smarty->assign($name, $value);
}
public function render()
{
$this->smarty->display($this->getTpl());
}
}

View File

@@ -96,6 +96,8 @@ class WebApplication
*/ */
public function route() public function route()
{ {
$this->requestUri = strlen($this->requestUri) > 1? rtrim($this->requestUri, '/'): $this->requestUri;
if ($this->requestUri === "/") { if ($this->requestUri === "/") {
if (file_exists("index.html")) { if (file_exists("index.html")) {
return self::RUNNING_INDEX; return self::RUNNING_INDEX;
@@ -107,7 +109,47 @@ class WebApplication
) { ) {
return self::RUNNING_API; return self::RUNNING_API;
} else { } else {
return self::RUNNING_WORKFLOW; list($this->requestUri,) = explode('?', $this->requestUri);
$uriParts = explode('/', $this->requestUri);
if ($uriParts[2] == 'oauth2') {
if (! isset($uriParts[2])) {
return self::RUNNING_WORKFLOW;
}
/*$workspace = $uriParts[1];
$class = 'oauth2';
$action = isset($uriParts[3])? $uriParts[3]: 'index';*/
$uriTemp = explode('/', $_SERVER['REQUEST_URI']);
array_shift($uriTemp);
$workspace = array_shift($uriTemp);
$_SERVER['REQUEST_URI'] = '/' . implode('/', $uriTemp);
$this->loadEnvironment($workspace);
$this->configureRest($workspace, '1.0');
//var_dump(class_exists('ProcessMaker\\Services\\OAuth2\\Server'));
$this->rest->addAPIClass('\ProcessMaker\\Services\\OAuth2\\Server', 'oauth2');
$this->rest->handle();
/*
$this->loadEnvironment($workspace);
require_once PATH_CONTROLLERS . $class . '.php';
if (is_callable(array($class, $action))) {
$controller = new $class();
$controller->setHttpRequestData($_REQUEST);
$controller->call($action);
} else {
header('location: /errors/error404?url=' . urlencode($this->requestUri));
}*/
} else {
return self::RUNNING_WORKFLOW;
}
} }
} }
@@ -227,8 +269,6 @@ class WebApplication
$apiIniFile = $servicesDir . DS . 'api.ini'; $apiIniFile = $servicesDir . DS . 'api.ini';
// $authenticationClass - contains the class name that validate the authentication for Restler // $authenticationClass - contains the class name that validate the authentication for Restler
$authenticationClass = 'ProcessMaker\\Services\\OAuth2\\Server'; $authenticationClass = 'ProcessMaker\\Services\\OAuth2\\Server';
// $pmOauthClientId - contains PM Local OAuth Id (Web Designer)
$pmOauthClientId = 'x-pm-local-client';
/* /*
* Load Api ini file for Rest Service * Load Api ini file for Rest Service
@@ -252,37 +292,9 @@ class WebApplication
} }
} }
// Setting current workspace to Api class $this->configureRest(SYS_SYS, $version, $multipart);
Services\Api::setWorkspace(SYS_SYS);
$cacheDir = defined("PATH_C")? PATH_C: sys_get_temp_dir();
$sysConfig = \System::getSystemConfiguration();
\Luracast\Restler\Defaults::$cacheDirectory = $cacheDir;
$productionMode = (bool) !(isset($sysConfig["service_api_debug"]) && $sysConfig["service_api_debug"]);
Util\Logger::log("Serving API mode: " . ($productionMode? "production": "development"));
// create a new Restler instance
//$rest = new \Luracast\Restler\Restler();
$this->rest = new \Maveriks\Extension\Restler($productionMode);
// setting flag for multipart to Restler
$this->rest->setFlagMultipart($multipart);
// setting api version to Restler
$this->rest->setAPIVersion($version);
// adding $authenticationClass to Restler
$this->rest->addAuthenticationClass($authenticationClass, ''); $this->rest->addAuthenticationClass($authenticationClass, '');
// Setting database connection source
list($host, $port) = strpos(DB_HOST, ':') !== false ? explode(':', DB_HOST) : array(DB_HOST, '');
$port = empty($port) ? '' : ";port=$port";
Services\OAuth2\Server::setDatabaseSource(DB_USER, DB_PASS, DB_ADAPTER.":host=$host;dbname=".DB_NAME.$port);
// Setting default OAuth Client id, for local PM Web Designer
Services\OAuth2\Server::setPmClientId($pmOauthClientId);
$this->rest->setOverridingFormats('JsonFormat', 'UploadFormat');
$isPluginRequest = strpos($uri, '/plugin-') !== false ? true : false; $isPluginRequest = strpos($uri, '/plugin-') !== false ? true : false;
if ($isPluginRequest) { if ($isPluginRequest) {
@@ -340,6 +352,44 @@ class WebApplication
} }
} }
public function configureRest($workspace, $version, $multipart = false)
{
// $pmOauthClientId - contains PM Local OAuth Id (Web Designer)
$pmOauthClientId = 'x-pm-local-client';
// Setting current workspace to Api class
Services\Api::setWorkspace($workspace);
$cacheDir = defined("PATH_C")? PATH_C: sys_get_temp_dir();
$sysConfig = \System::getSystemConfiguration();
\Luracast\Restler\Defaults::$cacheDirectory = $cacheDir;
$productionMode = false; //(bool) !(isset($sysConfig["service_api_debug"]) && $sysConfig["service_api_debug"]);
Util\Logger::log("Serving API mode: " . ($productionMode? "production": "development"));
// create a new Restler instance
//$rest = new \Luracast\Restler\Restler();
$this->rest = new \Maveriks\Extension\Restler($productionMode);
$this->rest->setworkspace($workspace);
// setting flag for multipart to Restler
$this->rest->setFlagMultipart($multipart);
// setting api version to Restler
$this->rest->setAPIVersion($version);
// adding $authenticationClass to Restler
// Setting database connection source
list($host, $port) = strpos(DB_HOST, ':') !== false ? explode(':', DB_HOST) : array(DB_HOST, '');
$port = empty($port) ? '' : ";port=$port";
Services\OAuth2\Server::setDatabaseSource(DB_USER, DB_PASS, DB_ADAPTER.":host=$host;dbname=".DB_NAME.$port);
// Setting default OAuth Client id, for local PM Web Designer
Services\OAuth2\Server::setPmClientId($pmOauthClientId);
Services\OAuth2\Server::setWorkspace($workspace);
$this->rest->setOverridingFormats('JsonFormat', 'UploadFormat');
}
public function parseApiRequestUri() public function parseApiRequestUri()
{ {
$url = explode("/", $this->requestUri); $url = explode("/", $this->requestUri);

View File

@@ -0,0 +1,118 @@
<?php
class Oauth2 extends Controller
{
public function index()
{
$http = (isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] == 'on') ? 'https' : 'http';
$host = $_SERVER['SERVER_NAME'] . ($_SERVER['SERVER_PORT'] != '80' ? ':' . $_SERVER['SERVER_PORT'] : '');
//$applicationsLink = sprintf('%s://%s/sys%s/%s/%s/oauth2/applications', $http, $host, SYS_SYS, SYS_LANG, SYS_SKIN);
$applicationsLink = sprintf('%s://%s/%s/oauth2/apps', $http, $host, SYS_SYS);
$authorizationLink = sprintf('%s://%s/%s/oauth2/authorize?response_type=code&client_id=[the-client-id]&scope=*', $http, $host, SYS_SYS);
//http://<your-pm-server>/sys<your-workspace>/en/neoclassic/oauth2/authorize?response_type=code&client_id={your-client-d}&scope=view_processes%20edit_processes
$this->setVar('applications_link', $applicationsLink);
$this->setVar('authorization_link', $authorizationLink);
$this->setView('oauth2/index');
$this->render();
}
public function apps()
{
$http = (isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] == 'on') ? 'https' : 'http';
$host = $_SERVER['SERVER_NAME'] . ($_SERVER['SERVER_PORT'] != '80' ? ':' . $_SERVER['SERVER_PORT'] : '');
$applicationsLink = sprintf('%s://%s/sys%s/%s/%s/oauth2/applications', $http, $host, SYS_SYS, SYS_LANG, SYS_SKIN);
header('location: ' . $applicationsLink);
}
public function authorize()
{
session_start();
if (! isset($_SESSION['USER_LOGGED'])) {
$http = (isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] == 'on') ? 'https' : 'http';
$host = $_SERVER['SERVER_NAME'] . ($_SERVER['SERVER_PORT'] != '80' ? ':' . $_SERVER['SERVER_PORT'] : '');
$loginLink = sprintf('%s://%s/sys%s/%s/%s/login/login?u=/%s/oauth2/authorize', $http, $host, SYS_SYS, SYS_LANG, SYS_SKIN, SYS_SYS);
header('location: ' . $loginLink);
die;
}
switch ($_SERVER['REQUEST_METHOD']) {
case 'GET':
require_once PATH_CORE . 'src/ProcessMaker/Services/OAuth2/PmPdo.php';
list($host, $port) = strpos(DB_HOST, ':') !== false ? explode(':', DB_HOST) : array(DB_HOST, '');
$port = empty($port) ? '' : ";port=$port";
$dsn = DB_ADAPTER.':host='.$host.';dbname='.DB_NAME.$port;
$username = DB_USER;
$password = DB_PASS;
$this->scope = array(
'view_processes' => 'View Processes',
'edit_processes' => 'Edit Processes'
);
// $dsn is the Data Source Name for your database, for example "mysql:dbname=my_oauth2_db;host=localhost"
$storage = new ProcessMaker\Services\OAuth2\PmPdo(array('dsn' => $dsn, 'username' => $username, 'password' => $password));
$clientId = $_GET['client_id'];
$requestedScope = isset($_GET['scope']) ? $_GET['scope'] : '';
$requestedScope = empty($requestedScope) ? array() : explode(' ', $requestedScope);
if (! empty($clientId)) {
$client = $storage->getClientDetails($clientId);
// throw error, client does not exist.
}
//echo '<pre>';print_r($client); echo '</pre>';
$client = array('name' => $client['client_name'], 'desc' => $client['client_description']);
//echo '<pre>';print_r($_SESSION); echo '</pre>'; die;
$user = array('name' => $_SESSION['USR_FULLNAME']);
$this->setVar('user', $user);
$this->setVar('client', $client);
$this->setVar('postUri', '/' . SYS_SYS . '/oauth2/authorize?' . $_SERVER['QUERY_STRING']);
//$this->setVar('postUri', '/' . SYS_SYS . '/oauth2/authorize');
//$this->setVar('query_string', $_SERVER['QUERY_STRING']);
$this->setView('oauth2/authorize');
$this->render();
break;
case 'POST':
require_once PATH_CORE . 'src/ProcessMaker/Services/OAuth2/Server.php';
list($host, $port) = strpos(DB_HOST, ':') !== false ? explode(':', DB_HOST) : array(DB_HOST, '');
$port = empty($port) ? '' : ";port=$port";
\ProcessMaker\Services\OAuth2\Server::setDatabaseSource(DB_USER, DB_PASS, DB_ADAPTER.":host=$host;dbname=".DB_NAME.$port);
\ProcessMaker\Services\OAuth2\Server::setPmClientId('x-pm-local-client');
$oauthServer = new \ProcessMaker\Services\OAuth2\Server();
$userid = $_SESSION['USER_LOGGED'];
$authorize = array_key_exists('cancel', $_POST)? false: true;
$response = $oauthServer->postAuthorize($authorize, $userid, true);
//$code = substr($response->getHttpHeader('Location'), strpos($response->getHttpHeader('Location'), 'code=')+5, 40);
//echo 'session_id ' . session_id() . '<br>';
//exit("SUCCESS! ==> Authorization Code: $code");
die($response->send());
break;
}
}
public function token()
{
}
}

View File

@@ -9,7 +9,7 @@ if (! empty($_GET['error'])) {
$http = (isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] == 'on') ? 'https' : 'http'; $http = (isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] == 'on') ? 'https' : 'http';
$host = $_SERVER['SERVER_NAME'] . ($_SERVER['SERVER_PORT'] != '80' ? ':' . $_SERVER['SERVER_PORT'] : ''); $host = $_SERVER['SERVER_NAME'] . ($_SERVER['SERVER_PORT'] != '80' ? ':' . $_SERVER['SERVER_PORT'] : '');
$endpoint = sprintf('%s://%s/api/1.0/%s/token', $http, $host, SYS_SYS); $endpoint = sprintf('%s://%s/%s/oauth2/token', $http, $host, SYS_SYS);
$code = empty($_GET['code']) ? 'NN' : $_GET['code']; $code = empty($_GET['code']) ? 'NN' : $_GET['code'];
$clientId = 'x-pm-local-client'; $clientId = 'x-pm-local-client';

View File

@@ -45,7 +45,7 @@ class PmPdo implements \OAuth2\Storage\AuthorizationCodeInterface,
'access_token_table' => 'OAUTH_ACCESS_TOKENS', 'access_token_table' => 'OAUTH_ACCESS_TOKENS',
'refresh_token_table' => 'OAUTH_REFRESH_TOKENS', 'refresh_token_table' => 'OAUTH_REFRESH_TOKENS',
'code_table' => 'OAUTH_AUTHORIZATION_CODES', 'code_table' => 'OAUTH_AUTHORIZATION_CODES',
'user_table' => 'OAUTH_USERS', 'user_table' => 'USERS',
'jwt_table' => 'OAUTH_JWT', 'jwt_table' => 'OAUTH_JWT',
), $config); ), $config);
} }
@@ -193,12 +193,12 @@ class PmPdo implements \OAuth2\Storage\AuthorizationCodeInterface,
// plaintext passwords are bad! Override this for your application // plaintext passwords are bad! Override this for your application
protected function checkPassword($user, $password) protected function checkPassword($user, $password)
{ {
return $user['password'] == sha1($password); return $user['USR_PASSWORD'] == md5($password);
} }
public function getUser($username) public function getUser($username)
{ {
$stmt = $this->db->prepare($sql = sprintf('SELECT * FROM %s WHERE USERNAME=:username', $this->config['user_table'])); $stmt = $this->db->prepare($sql = sprintf('SELECT * FROM %s WHERE USR_USERNAME=:username', $this->config['user_table']));
$stmt->execute(array('username' => $username)); $stmt->execute(array('username' => $username));
if (!$userInfo = $stmt->fetch()) { if (!$userInfo = $stmt->fetch()) {

View File

@@ -2,6 +2,7 @@
namespace ProcessMaker\Services\OAuth2; namespace ProcessMaker\Services\OAuth2;
use Luracast\Restler\iAuthenticate; use Luracast\Restler\iAuthenticate;
use Luracast\Restler\RestException;
/** /**
@@ -28,6 +29,7 @@ class Server implements iAuthenticate
protected static $dbUser; protected static $dbUser;
protected static $dbPassword; protected static $dbPassword;
protected static $dsn; protected static $dsn;
protected static $workspace;
public function __construct() public function __construct()
{ {
@@ -35,7 +37,8 @@ class Server implements iAuthenticate
$this->scope = array( $this->scope = array(
'view_processes' => 'View Processes', 'view_processes' => 'View Processes',
'edit_processes' => 'Edit Processes' 'edit_processes' => 'Edit Processes',
'*' => '*'
); );
// $dsn is the Data Source Name for your database, for exmaple "mysql:dbname=my_oauth2_db;host=localhost" // $dsn is the Data Source Name for your database, for exmaple "mysql:dbname=my_oauth2_db;host=localhost"
@@ -44,7 +47,7 @@ class Server implements iAuthenticate
$this->storage = new PmPdo($config); $this->storage = new PmPdo($config);
// Pass a storage object or array of storage objects to the OAuth2 server class // Pass a storage object or array of storage objects to the OAuth2 server class
$this->server = new \OAuth2\Server($this->storage); $this->server = new \OAuth2\Server($this->storage, array('allow_implicit' => true));
$this->server->setConfig('enforce_state', false); $this->server->setConfig('enforce_state', false);
@@ -52,14 +55,21 @@ class Server implements iAuthenticate
$this->server->addGrantType(new \OAuth2\GrantType\AuthorizationCode($this->storage)); $this->server->addGrantType(new \OAuth2\GrantType\AuthorizationCode($this->storage));
// Add the "Client Credentials" grant type (it is the simplest of the grant types) // Add the "Client Credentials" grant type (it is the simplest of the grant types)
//$this->server->addGrantType(new \OAuth2\GrantType\ClientCredentials($this->storage)); $this->server->addGrantType(new \OAuth2\GrantType\ClientCredentials($this->storage));
// Add the "Refresh token" grant type // Add the "Refresh token" grant type
$this->server->addGrantType(new \OAuth2\GrantType\RefreshToken($this->storage)); $this->server->addGrantType(new \OAuth2\GrantType\RefreshToken($this->storage));
$scope = new \OAuth2\Scope(array( // create some users in memory
'supported_scopes' => array_keys($this->scope) //$users = array('bshaffer' => array('password' => 'brent123', 'first_name' => 'Brent', 'last_name' => 'Shaffer'));
)); // create a storage object
//$storage = new \OAuth2\Storage\Memory(array('user_credentials' => $users));
// create the grant type
$grantType = new \OAuth2\GrantType\UserCredentials($this->storage);
// add the grant type to your OAuth server
$this->server->addGrantType($grantType);
$scope = new \OAuth2\Scope(array('supported_scopes' => array_keys($this->scope)));
$this->server->setScopeUtil($scope); $this->server->setScopeUtil($scope);
} }
@@ -76,6 +86,28 @@ class Server implements iAuthenticate
} }
} }
public static function setWorkspace($workspace)
{
self::$workspace = $workspace;
}
public function index()
{
$http = (isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] == 'on') ? 'https' : 'http';
$host = $_SERVER['SERVER_NAME'] . ($_SERVER['SERVER_PORT'] != '80' ? ':' . $_SERVER['SERVER_PORT'] : '');
$host = $http .'://'. $host;
$applicationsLink = sprintf('%s/%s/oauth2/apps', $host, SYS_SYS);
$authorizationLink = sprintf('%s/%s/oauth2/authorize?response_type=code&client_id=[the-client-id]&scope=*', $host, SYS_SYS);
$view = new \Maveriks\Pattern\Mvc\SmartyView(PATH_CORE . "templates/oauth2/index.html");
$view->assign('host', $host);
$view->assign('workspace', self::$workspace);
$view->render();
}
/** /**
* @view oauth2/server/register.php * @view oauth2/server/register.php
* @format HtmlFormat * @format HtmlFormat
@@ -91,25 +123,53 @@ class Server implements iAuthenticate
* *
* User responds by accepting or denying * User responds by accepting or denying
* *
* @view oauth2/server/authorize.php
* @format HtmlFormat
*/ */
public function authorize() public function authorize()
{ {
$clientId = \OAuth2\Request::createFromGlobals()->query('client_id', ''); session_start();
$requestedScope = \OAuth2\Request::createFromGlobals()->query('scope', '');
$requestedScope = empty($requestedScope) ? array() : explode(' ', $requestedScope);
if (! empty($clientId)) { if (! isset($_SESSION['USER_LOGGED'])) {
$clientDetails = $this->storage->getClientDetails(\OAuth2\Request::createFromGlobals()->query('client_id')); $http = (isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] == 'on') ? 'https' : 'http';
$host = $http . '://' . $_SERVER['SERVER_NAME'] . ($_SERVER['SERVER_PORT'] != '80' ? ':' . $_SERVER['SERVER_PORT'] : '');
$redirect = urlencode($host.'/'.self::$workspace.$_SERVER['REQUEST_URI']);
$loginLink = sprintf('%s/sys%s/%s/%s/login/login?u=%s', $host, SYS_SYS, SYS_LANG, SYS_SKIN, $redirect);
header('location: ' . $loginLink);
die;
} }
return array( $this->scope = array(
'client_details' => $clientDetails, 'view_processes' => 'View Processes',
'query_string' => $_SERVER['QUERY_STRING'], 'edit_processes' => 'Edit Processes'
'supportedScope' => $this->scope,
'requestedScope' => $requestedScope
); );
if (! array_key_exists('client_id', $_GET)) {
throw new RestException(400, "Invalid request. The 'client_id' parameter is missing!");
}
if (! array_key_exists('response_type', $_GET)) {
throw new RestException(400, "Invalid request. The 'response_type' parameter is missing!");
}
$clientId = $_GET['client_id'];
$requestedScope = isset($_GET['scope']) ? $_GET['scope'] : '*';
$requestedScope = empty($requestedScope) ? array() : explode(' ', $requestedScope);
$client = $this->storage->getClientDetails($clientId);;
if (empty($client)) {
// throw error, client does not exist.
throw new RestException(400, "Error, unknown client. The client with id '".$clientId."' is not registered");
}
//echo '<pre>';print_r($client); echo '</pre>'; die;
$client = array('name' => $client['client_name'], 'desc' => $client['client_description']);
$user = array('name' => $_SESSION['USR_FULLNAME']);
$view = new \Maveriks\Pattern\Mvc\SmartyView(PATH_CORE . "templates/oauth2/authorize.html");
$view->assign('user', $user);
$view->assign('client', $client);
$view->assign('postUri', '/' . SYS_SYS . '/oauth2/authorize?' . $_SERVER['QUERY_STRING']);
$view->render();
exit();
} }
/** /**
@@ -120,15 +180,19 @@ class Server implements iAuthenticate
* *
* On success authorization code is sent along * On success authorization code is sent along
* *
*
* @param bool $authorize
* @param string $userId optional user id
* @param bool $returnResponse optional flag to specify if the function should return the Response object
* @return \OAuth2\ResponseInterface
* @format JsonFormat,UploadFormat * @format JsonFormat,UploadFormat
*/ */
public function postAuthorize($authorize = false, $userId = null, $returnResponse = false) public function postAuthorize()
{ {
session_start();
if (! isset($_SESSION['USER_LOGGED'])) {
throw new RestException(400, "Local Authentication Error, user session is not started.");
}
$userId = $_SESSION['USER_LOGGED'];
$authorize = array_key_exists('cancel', $_REQUEST)? false: true;
$request = \OAuth2\Request::createFromGlobals(); $request = \OAuth2\Request::createFromGlobals();
$response = new \OAuth2\Response(); $response = new \OAuth2\Response();
@@ -139,10 +203,6 @@ class Server implements iAuthenticate
$userId $userId
); );
if ($returnResponse) {
return $response;
}
die($response->send()); die($response->send());
} }

View File

@@ -0,0 +1,52 @@
<!doctype html>
<html>
<head>
<title>ProcessMaker Oauth2 Server</title>
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<!-- Style sheets -->
<link rel="stylesheet" type="text/css" href="/assets/css/pure-min.css">
<link rel="stylesheet" href="/assets/css/base-min.css">
<link rel="stylesheet" type="text/css" href="/assets/css/grids-responsive-min.css">
<script type="text/javascript" src="/assets/js/jquery.min.js"></script>
<link rel="stylesheet" type="text/css" href="/assets/css/oauth2.css">
</head>
<body>
<form action="{$postUri}" method="post" class="pure-form pure-form-stacked" enctype="application/x-www-form-urlencoded">
<input name="transaction_id" type="hidden" value="{$transactionID}">
<fieldset>
<!-- Upper box with Title, username, and password -->
<div class="upper-box">
<!-- Title -->
<div style="padding-top: 15px">
<img style="display: block; margin-left: auto; margin-right: auto;" src="/images/processmaker.logo.jpg">
<div class="subtext">Authorization Server</div>
</div>
<div class="pure-control-group labels">
<p>
<p>{$user.name},</p>
The application <b>{$client.name}</b> is requesting access to your account.
<h4>{$client.client_name}</h4>
<small><i>{$client.desc}</i></small>
</p>
<p>Do you approve?</p>
</div>
</div>
<!-- Bottom box with Sign in -->
<div class="bottom-box">
<div class="pure-controls accept-cancel-buttons">
<div>
<input class="pure-button pure-button-primary" type="submit" value="Accept" id="allow">
<!-- Cheat to make a bit of spacing -->
<span>&nbsp&nbsp</span>
<input class="pure-button" type="submit" value="Deny" name="cancel" id="deny">
</div>
</div>
</div>
</fieldset>
</form>

View File

@@ -0,0 +1,210 @@
<!doctype html>
<html>
<head>
<title>ProcessMaker Oauth2 Server</title>
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<!-- Style sheets -->
<link rel="stylesheet" type="text/css" href="/assets/css/pure-min.css">
<link rel="stylesheet" href="/assets/css/base-min.css">
<link rel="stylesheet" type="text/css" href="/assets/css/grids-responsive-min.css">
<script type="text/javascript" src="/assets/js/jquery.min.js"></script>
<link rel="stylesheet" type="text/css" href="/assets/css/oauth2.css">
</head>
<body>
<div id="layout" class="pure-g">
<div class="sidebar pure-u-1 pure-u-md-1-4">
<div class="header">
<hgroup>
<h2 class="brand-title">ProcessMaker</h2>
<h3 class="brand-tagline">Authorization Server</h3>
<h4 class="brand-tagline">OAuth v2</h4>
</hgroup>
<!--<nav class="nav">
<ul class="nav-list">
<li class="nav-item">
<a class="pure-button" href="#">AAA</a>
</li>
<li class="nav-item">
<a class="pure-button" href="#">BBB</a>
</li>
</ul>
</nav>-->
</div>
</div>
<div class="content pure-u-1 pure-u-md-3-4">
<div>
<!-- A wrapper for all the blog posts -->
<div class="posts">
<h1 class="content-subhead">Authorization Code</h1>
<section class="post">
<header class="post-header">
<h2 class="post-title">Authorization Code</h2>
<p class="post-meta">
See RFC <a href="http://tools.ietf.org/html/rfc6749#section-4.1" target="_blank" class="post-author">Authorization Code Grant</a>
</p>
</header>
<div class="post-description">
<p>
The authorization code grant type is used to obtain both access tokens and refresh tokens and is optimized for
confidential clients.<br/>
<ol>
<li>
Register the application
<pre>
GET {$host}/{$workspace}/oauth2/apps</pre>
</li>
<li>
Request Authorization
<pre>
GET {$host}/{$workspace}/oauth2/authorize?response_type=code&client_id={literal}{the-client-id}{/literal}&scope=*</pre>
</li>
<li>
Exchange Authorization code by an Access Token.
<pre>
POST {$host}/{$workspace}/oauth2/token
Authorization: Basic eC1wbS1sb2NhbC1jbGllbnQ6MTc5YWQ0NWM2Y2UyY2I5N2NmMTAyOWUyMTIwNDZlODE=
grant_type=code&
code={literal}{the-authorization-code}{/literal}
</pre>
</li>
</ol>
<p><a id="authcode" href="{$auth_code_link}">{$auth_code_link}</a></p>
</p>
</div>
</section>
<h1 class="content-subhead">Implicit Grant</h1>
<section class="post">
<header class="post-header">
<h2 class="post-title">Implicit Grant</h2>
<p class="post-meta">
See RFC <a href="http://tools.ietf.org/html/rfc6749#section-4.2" target="_blank" class="post-author">Implicit Grant</a>
</p>
</header>
<div class="post-description">
<p>
The implicit grant type is used to obtain access tokens (it does not support the issuance of refresh tokens) and
is optimized for public clients known to operate a particular redirection URI.
<pre>GET {$host}/{$workspace}/oauth2/authorize?response_type=token&client_id={literal}{the-client-id}{/literal}&scope=*</pre>
</div>
</section>
<h1 class="content-subhead">Resource Owner Password Credentials</h1>
<section class="post">
<header class="post-header">
<h2 class="post-title">Resource Owner Password Credentials</h2>
<p class="post-meta">
See RFC <a href="http://tools.ietf.org/html/rfc6749#section-4.3" target="_blank" class="post-author">Resource Owner Password Credentials</a>
</p>
</header>
<div class="post-description">
<p>
The resource owner password credentials grant type is suitable in cases where the resource owner has a trust
relationship with the client, such as the device operating system or a highly privileged application.<br/><br/>
<pre>
POST {$host}/{$workspace}/oauth2/token
Content-Type: application/x-www-form-urlencoded
Authorization: Basic eC1wbS1sb2NhbC1jbGllbnQ6MTc5YWQ0NWM2Y2UyY2I5N2NmMTAyOWUyMTIwNDZlODE=
grant_type=password&
username=bob&
password=secret&
scope=offline_access
</pre>
</p>
</div>
</section>
<h1 class="content-subhead">Client Credentials</h1>
<section class="post">
<header class="post-header">
<h2 class="post-title">Client Credentials</h2>
<p class="post-meta">
See RFC <a href="http://tools.ietf.org/html/rfc6749#section-4.4" target="_blank" class="post-author">Client Credentials</a>
</p>
</header>
<div class="post-description">
<p>
The client can request an access token using only its client credentials (or other supported means of authentication)
when the client is requesting access to the protected resources under its control, or those of another resource
owner that have been previously arranged with the authorization server. <br/><br/>
<pre>
POST {$host}/{$workspace}/oauth/2/token
Content-Type: application/x-www-form-urlencoded
Authorization: Basic eC1wbS1sb2NhbC1jbGllbnQ6MTc5YWQ0NWM2Y2UyY2I5N2NmMTAyOWUyMTIwNDZlODE=
grant_type=client_credentials
</pre>
</p>
</div>
</section>
<h1 class="content-subhead">Refresh Token</h1>
<section class="post">
<header class="post-header">
<h2 class="post-title">Refresh Token</h2>
<p class="post-meta">
See RFC <a href="http://tools.ietf.org/html/rfc6749#section-1.5" target="_blank" class="post-author">Refresh Token</a>
</p>
</header>
<div class="post-description">
<p>
Refresh tokens are credentials used to obtain access tokens. Refresh
tokens are issued to the client by the authorization server and are
used to obtain a new access token when the current access token
becomes invalid or expires, or to obtain additional access tokens
with identical or narrower scope (access tokens may have a shorter
lifetime and fewer permissions than authorized by the resource
owner). Issuing a refresh token is optional at the discretion of the
authorization server. If the authorization server issues a refresh
token, it is included when issuing an access token. <br/><br/>
<pre>
POST {$host}/{$workspace}/oauth2/token
Content-Type: application/x-www-form-urlencoded
Authorization: Basic eC1wbS1sb2NhbC1jbGllbnQ6MTc5YWQ0NWM2Y2UyY2I5N2NmMTAyOWUyMTIwNDZlODE=
grant_type=refresh_token
refresh_token={literal}{your-refresh-token}{/literal}
</pre>
</p>
</div>
</section>
</div>
<div class="footer">
<div class="pure-menu pure-menu-horizontal pure-menu-open">
<ul>
<li><a href="http://processmaker.com/">ProcessMaker</a></li>
</ul>
</div>
</div>
</div>
</div>
</div>
</body>
</html>

View File

@@ -0,0 +1,11 @@
/*!
Pure v0.5.0
Copyright 2014 Yahoo! Inc. All rights reserved.
Licensed under the BSD License.
https://github.com/yui/pure/blob/master/LICENSE.md
*/
/*!
normalize.css v1.1.3 | MIT License | git.io/normalize
Copyright (c) Nicolas Gallagher and Jonathan Neal
*/
/*! normalize.css v1.1.3 | MIT License | git.io/normalize */article,aside,details,figcaption,figure,footer,header,hgroup,main,nav,section,summary{display:block}audio,canvas,video{display:inline-block;*display:inline;*zoom:1}audio:not([controls]){display:none;height:0}[hidden]{display:none}html{font-size:100%;-ms-text-size-adjust:100%;-webkit-text-size-adjust:100%}html,button,input,select,textarea{font-family:sans-serif}body{margin:0}a:focus{outline:thin dotted}a:active,a:hover{outline:0}h1{font-size:2em;margin:.67em 0}h2{font-size:1.5em;margin:.83em 0}h3{font-size:1.17em;margin:1em 0}h4{font-size:1em;margin:1.33em 0}h5{font-size:.83em;margin:1.67em 0}h6{font-size:.67em;margin:2.33em 0}abbr[title]{border-bottom:1px dotted}b,strong{font-weight:700}blockquote{margin:1em 40px}dfn{font-style:italic}hr{-moz-box-sizing:content-box;box-sizing:content-box;height:0}mark{background:#ff0;color:#000}p,pre{margin:1em 0}code,kbd,pre,samp{font-family:monospace,serif;_font-family:'courier new',monospace;font-size:1em}pre{white-space:pre;white-space:pre-wrap;word-wrap:break-word}q{quotes:none}q:before,q:after{content:'';content:none}small{font-size:80%}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}sup{top:-.5em}sub{bottom:-.25em}dl,menu,ol,ul{margin:1em 0}dd{margin:0 0 0 40px}menu,ol,ul{padding:0 0 0 40px}nav ul,nav ol{list-style:none;list-style-image:none}img{border:0;-ms-interpolation-mode:bicubic}svg:not(:root){overflow:hidden}figure{margin:0}form{margin:0}fieldset{border:1px solid silver;margin:0 2px;padding:.35em .625em .75em}legend{border:0;padding:0;white-space:normal;*margin-left:-7px}button,input,select,textarea{font-size:100%;margin:0;vertical-align:baseline;*vertical-align:middle}button,input{line-height:normal}button,select{text-transform:none}button,html input[type=button],input[type=reset],input[type=submit]{-webkit-appearance:button;cursor:pointer;*overflow:visible}button[disabled],html input[disabled]{cursor:default}input[type=checkbox],input[type=radio]{box-sizing:border-box;padding:0;*height:13px;*width:13px}input[type=search]{-webkit-appearance:textfield;-moz-box-sizing:content-box;-webkit-box-sizing:content-box;box-sizing:content-box}input[type=search]::-webkit-search-cancel-button,input[type=search]::-webkit-search-decoration{-webkit-appearance:none}button::-moz-focus-inner,input::-moz-focus-inner{border:0;padding:0}textarea{overflow:auto;vertical-align:top}table{border-collapse:collapse;border-spacing:0}[hidden]{display:none!important}.pure-img{max-width:100%;height:auto;display:block}

View File

@@ -0,0 +1,197 @@
/**
* Coloring h1 a bit off black, removing bold, and shadowing
* a touch.
*/
h1 {
color: #505050;
text-shadow: 2px 1px 3px rgba(200, 200, 200, 0.43);
font-weight: normal;
}
/**
* Using some off white for the background color and
* padding the top.
*/
body
{
background: whitesmoke;
padding-top: 60px;
}
/**
* Make links smaller,
*/
a
{
text-shadow: 2px 1px 3px rgba(200, 200, 200, 0.43);
padding-bottom: 5px;
padding-top: 10px;
font-size: 80%;
color: #6464ff;
text-decoration: none;
}
pre
{
margin-top: 0px;
margin-bottom: 0px;
}
.title {
width: 500px;
margin-left: auto;
margin-right: auto;
}
/**
* Upper box that contains the title Authorization Server, the UserName, and Password fields
*/
.upper-box {
width: 350px;
border-top: 1px solid;
border-left: 1px solid;
border-right: 1px solid;
border-color: lightgrey;
border-top-left-radius: 3px;
border-top-right-radius: 3px;
padding-top: 5px;
padding-left: 20px;
padding-bottom: 10px;
box-shadow: 1px 1px 5px #e7e7e7;
margin-left: auto;
margin-right: auto;
/**
* Gradient calculated from gradient calculator of
* http://gradients.glrzad.com/
*/
background-image: linear-gradient(bottom, rgb(249,250,252) 21%, rgb(245,247,250) 67%, rgb(247,249,255) 94%);
background-image: -o-linear-gradient(bottom, rgb(249,250,252) 21%, rgb(245,247,250) 67%, rgb(247,249,255) 94%);
background-image: -moz-linear-gradient(bottom, rgb(249,250,252) 21%, rgb(245,247,250) 67%, rgb(247,249,255) 94%);
background-image: -webkit-linear-gradient(bottom, rgb(249,250,252) 21%, rgb(245,247,250) 67%, rgb(247,249,255) 94%);
background-image: -ms-linear-gradient(bottom, rgb(249,250,252) 21%, rgb(245,247,250) 67%, rgb(247,249,255) 94%);
background-image: -webkit-gradient(
linear,
left bottom,
left top,
color-stop(0.21, rgb(249,250,252)),
color-stop(0.67, rgb(245,247,250)),
color-stop(0.94, rgb(247,249,255))
);
}
/**
* Bottom box that contains the "Sign in" button
*/
.bottom-box {
border:1px solid;
border-color: lightgrey;
border-bottom-right-radius: 5px;
border-bottom-left-radius: 5px;
width: 350px;
padding-top: 15px;
padding-left: 20px;
padding-bottom: 15px;
box-shadow: 1px 3px 1px #e7e7e7;
margin-left: auto;
margin-right: auto;
/**
* Gradient calculated from gradient calculator of
* http://gradients.glrzad.com/
*/
background-image: linear-gradient(bottom, rgb(242,245,250) 21%, rgb(242,245,250) 67%, rgb(242,245,255) 94%);
background-image: -o-linear-gradient(bottom, rgb(242,245,250) 21%, rgb(242,245,250) 67%, rgb(242,245,255) 94%);
background-image: -moz-linear-gradient(bottom, rgb(242,245,250) 21%, rgb(242,245,250) 67%, rgb(242,245,255) 94%);
background-image: -webkit-linear-gradient(bottom, rgb(242,245,250) 21%, rgb(242,245,250) 67%, rgb(242,245,255) 94%);
background-image: -ms-linear-gradient(bottom, rgb(242,245,250) 21%, rgb(242,245,250) 67%, rgb(242,245,255) 94%);
background-image: -webkit-gradient(
linear,
left bottom,
left top,
color-stop(0.21, rgb(242,245,250)),
color-stop(0.67, rgb(242,245,250)),
color-stop(0.94, rgb(242,245,255))
);
}
/**
* Okay, you caught me. It's a hack to make this look centered.
*
* TODO Fix this, can't figure out how to get this to center correctly.
* It's currently anchored to the fieldset and that's causing issues.
*/
.main-text {
padding-left: 100px;
padding-top: 20px;
font-size: 180%;
color: #505050;
text-shadow: 2px 1px 3px rgba(200, 200, 200, 0.43);
font-weight: normal;
}
/**
* Okay, you caught me. It's a hack to make this look centered.
*
* TODO Fix this, can't figure out how to get this to center correctly.
* It's currently anchored to the fieldset and that's causing issues.
*/
.subtext {
padding-left: 80px;
font-size: 110%;
color: #969696;
text-shadow: 2px 1px 3px rgba(230, 230, 230, 0.42);
font-weight: normal;
}
/**
* The username and password labels
*/
.labels {
color: #505050;
text-shadow: 2px 1px 3px rgba(200, 200, 200, 0.43);
padding-top: 10px;
}
/**
* Input fields so I can make it slightly larger than the default,
* and I can also pad anything trying to touch it on the right.
*/
.input-fields {
padding-right: 20px;
font-size: 130%;
}
/**
* This makes all the placeholder text italic. Nice trick I
* picked up from stack overflow:
* http://stackoverflow.com/questions/16291925/how-to-make-value-text-in-form-be-italic
*/
::-webkit-input-placeholder { font-style: italic; }
::-moz-placeholder { font-style: italic; }
:-ms-input-placeholder { font-style: italic; }
/**
* Very specific to the sign on button.
*/
.accept-cancel-buttons {
padding-left: 20px;
padding-right: 20px;
text-align: right;
}
.from-text {
padding-top: 10px;
text-align: center;
}

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,368 @@
* {
-webkit-box-sizing: border-box;
-moz-box-sizing: border-box;
box-sizing: border-box;
}
a {
text-decoration: none;
color: rgb(61, 146, 201);
}
a:hover,
a:focus {
text-decoration: underline;
}
h3 {
font-weight: 100;
}
/* LAYOUT CSS */
.pure-img-responsive {
max-width: 100%;
height: auto;
}
#layout {
padding: 0;
}
.header {
text-align: center;
top: auto;
margin: 3em auto;
}
.sidebar {
background: rgb(61, 79, 93);
color: #fff;
}
.brand-title,
.brand-tagline {
margin: 0;
}
.brand-title {
text-transform: uppercase;
}
.brand-tagline {
font-weight: 300;
color: rgb(176, 202, 219);
}
.nav-list {
margin: 0;
padding: 0;
list-style: none;
}
.nav-item {
display: inline-block;
*display: inline;
zoom: 1;
}
.nav-item a {
background: transparent;
border: 2px solid rgb(176, 202, 219);
color: #fff;
margin-top: 1em;
letter-spacing: 0.05em;
text-transform: uppercase;
font-size: 85%;
}
.nav-item a:hover,
.nav-item a:focus {
border: 2px solid rgb(61, 146, 201);
text-decoration: none;
}
.content-subhead {
text-transform: uppercase;
color: #aaa;
border-bottom: 1px solid #eee;
padding: 0.4em 0;
font-size: 80%;
font-weight: 500;
letter-spacing: 0.1em;
}
.content {
padding: 2em 1em 0;
}
.post {
padding-bottom: 2em;
}
.post-title {
font-size: 2em;
color: #222;
margin-bottom: 0.2em;
}
.post-avatar {
border-radius: 50px;
float: right;
margin-left: 1em;
}
.post-description {
font-family: Georgia, "Cambria", serif;
color: #444;
line-height: 1.8em;
}
.post-meta {
color: #999;
font-size: 90%;
margin: 0;
}
.post-category {
margin: 0 0.1em;
padding: 0.3em 1em;
color: #fff;
background: #999;
font-size: 80%;
}
.post-category-design {
background: #5aba59;
}
.post-category-pure {
background: #4d85d1;
}
.post-category-yui {
background: #8156a7;
}
.post-category-js {
background: #df2d4f;
}
.post-images {
margin: 1em 0;
}
.post-image-meta {
margin-top: -3.5em;
margin-left: 1em;
color: #fff;
text-shadow: 0 1px 1px #333;
}
.footer {
text-align: center;
padding: 1em 0;
}
.footer a {
color: #ccc;
font-size: 80%;
}
.footer .pure-menu a:hover,
.footer .pure-menu a:focus {
background: none;
}
@media (min-width: 48em) {
.content {
padding: 2em 3em 0;
margin-left: 25%;
}
.header {
margin: 80% 2em 0;
text-align: right;
}
.sidebar {
position: fixed;
top: 0;
bottom: 0;
}
}
pre {
font-size: 14px;
}
/**
* Coloring h1 a bit off black, removing bold, and shadowing
* a touch.
*/
h1 {
color: #505050;
text-shadow: 2px 1px 3px rgba(200, 200, 200, 0.43);
font-weight: normal;
}
/**
* Using some off white for the background color and
* padding the top.
*/
body
{
background: whitesmoke;
padding-top: 60px;
}
/**
* Make links smaller,
*/
pre
{
margin-top: 0px;
margin-bottom: 0px;
}
.title {
width: 500px;
margin-left: auto;
margin-right: auto;
}
/**
* Upper box that contains the title Authorization Server, the UserName, and Password fields
*/
.upper-box {
width: 350px;
border-top: 1px solid;
border-left: 1px solid;
border-right: 1px solid;
border-color: lightgrey;
border-top-left-radius: 3px;
border-top-right-radius: 3px;
padding-top: 5px;
padding-left: 20px;
padding-bottom: 10px;
box-shadow: 1px 1px 5px #e7e7e7;
margin-left: auto;
margin-right: auto;
/**
* Gradient calculated from gradient calculator of
* http://gradients.glrzad.com/
*/
background-image: linear-gradient(bottom, rgb(249,250,252) 21%, rgb(245,247,250) 67%, rgb(247,249,255) 94%);
background-image: -o-linear-gradient(bottom, rgb(249,250,252) 21%, rgb(245,247,250) 67%, rgb(247,249,255) 94%);
background-image: -moz-linear-gradient(bottom, rgb(249,250,252) 21%, rgb(245,247,250) 67%, rgb(247,249,255) 94%);
background-image: -webkit-linear-gradient(bottom, rgb(249,250,252) 21%, rgb(245,247,250) 67%, rgb(247,249,255) 94%);
background-image: -ms-linear-gradient(bottom, rgb(249,250,252) 21%, rgb(245,247,250) 67%, rgb(247,249,255) 94%);
background-image: -webkit-gradient(
linear,
left bottom,
left top,
color-stop(0.21, rgb(249,250,252)),
color-stop(0.67, rgb(245,247,250)),
color-stop(0.94, rgb(247,249,255))
);
}
/**
* Bottom box that contains the "Sign in" button
*/
.bottom-box {
border:1px solid;
border-color: lightgrey;
border-bottom-right-radius: 5px;
border-bottom-left-radius: 5px;
width: 350px;
padding-top: 15px;
padding-left: 20px;
padding-bottom: 15px;
box-shadow: 1px 3px 1px #e7e7e7;
margin-left: auto;
margin-right: auto;
/**
* Gradient calculated from gradient calculator of
* http://gradients.glrzad.com/
*/
background-image: linear-gradient(bottom, rgb(242,245,250) 21%, rgb(242,245,250) 67%, rgb(242,245,255) 94%);
background-image: -o-linear-gradient(bottom, rgb(242,245,250) 21%, rgb(242,245,250) 67%, rgb(242,245,255) 94%);
background-image: -moz-linear-gradient(bottom, rgb(242,245,250) 21%, rgb(242,245,250) 67%, rgb(242,245,255) 94%);
background-image: -webkit-linear-gradient(bottom, rgb(242,245,250) 21%, rgb(242,245,250) 67%, rgb(242,245,255) 94%);
background-image: -ms-linear-gradient(bottom, rgb(242,245,250) 21%, rgb(242,245,250) 67%, rgb(242,245,255) 94%);
background-image: -webkit-gradient(
linear,
left bottom,
left top,
color-stop(0.21, rgb(242,245,250)),
color-stop(0.67, rgb(242,245,250)),
color-stop(0.94, rgb(242,245,255))
);
}
/**
* Okay, you caught me. It's a hack to make this look centered.
*
* TODO Fix this, can't figure out how to get this to center correctly.
* It's currently anchored to the fieldset and that's causing issues.
*/
.main-text {
padding-left: 100px;
padding-top: 20px;
font-size: 180%;
color: #505050;
text-shadow: 2px 1px 3px rgba(200, 200, 200, 0.43);
font-weight: normal;
}
/**
* Okay, you caught me. It's a hack to make this look centered.
*
* TODO Fix this, can't figure out how to get this to center correctly.
* It's currently anchored to the fieldset and that's causing issues.
*/
.subtext {
padding-left: 80px;
font-size: 110%;
color: #969696;
text-shadow: 2px 1px 3px rgba(230, 230, 230, 0.42);
font-weight: normal;
}
/**
* The username and password labels
*/
.labels {
color: #505050;
text-shadow: 2px 1px 3px rgba(200, 200, 200, 0.43);
padding-top: 10px;
}
/**
* Input fields so I can make it slightly larger than the default,
* and I can also pad anything trying to touch it on the right.
*/
.input-fields {
padding-right: 20px;
font-size: 130%;
}
/**
* This makes all the placeholder text italic. Nice trick I
* picked up from stack overflow:
* http://stackoverflow.com/questions/16291925/how-to-make-value-text-in-form-be-italic
*/
::-webkit-input-placeholder { font-style: italic; }
::-moz-placeholder { font-style: italic; }
:-ms-input-placeholder { font-style: italic; }
/**
* Very specific to the sign on button.
*/
.accept-cancel-buttons {
padding-left: 20px;
padding-right: 20px;
text-align: right;
}
.from-text {
padding-top: 10px;
text-align: center;
}

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,174 @@
/**
* Coloring h1 a bit off black, removing bold, and shadowing
* a touch.
*/
h1 {
color: #505050;
text-shadow: 2px 1px 3px rgba(200, 200, 200, 0.43);
font-weight: normal;
}
/**
* Using some off white for the background color and
* padding the top.
*/
body
{
background: whitesmoke;
padding-top: 60px;
}
/**
* Make links smaller,
*/
a
{
text-shadow: 2px 1px 3px rgba(200, 200, 200, 0.43);
padding-bottom: 5px;
padding-top: 10px;
font-size: 80%;
color: #6464ff;
text-decoration: none;
}
pre
{
margin-top: 0px;
margin-bottom: 0px;
}
/**
* Upper box that contains the title Authorization Server, the UserName, and Password fields
*/
.upper-box {
width: 350px;
border-top: 1px solid;
border-left: 1px solid;
border-right: 1px solid;
border-color: lightgrey;
border-top-left-radius: 3px;
border-top-right-radius: 3px;
padding-top: 5px;
padding-left: 20px;
padding-bottom: 35px;
box-shadow: 1px 1px 5px #e7e7e7;
margin-left: auto;
margin-right: auto;
/**
* Gradient calculated from gradient calculator of
* http://gradients.glrzad.com/
*/
background-image: linear-gradient(bottom, rgb(249,250,252) 21%, rgb(245,247,250) 67%, rgb(247,249,255) 94%);
background-image: -o-linear-gradient(bottom, rgb(249,250,252) 21%, rgb(245,247,250) 67%, rgb(247,249,255) 94%);
background-image: -moz-linear-gradient(bottom, rgb(249,250,252) 21%, rgb(245,247,250) 67%, rgb(247,249,255) 94%);
background-image: -webkit-linear-gradient(bottom, rgb(249,250,252) 21%, rgb(245,247,250) 67%, rgb(247,249,255) 94%);
background-image: -ms-linear-gradient(bottom, rgb(249,250,252) 21%, rgb(245,247,250) 67%, rgb(247,249,255) 94%);
background-image: -webkit-gradient(
linear,
left bottom,
left top,
color-stop(0.21, rgb(249,250,252)),
color-stop(0.67, rgb(245,247,250)),
color-stop(0.94, rgb(247,249,255))
);
}
/**
* Bottom box that contains the "Sign in" button
*/
.bottom-box {
border:1px solid;
border-color: lightgrey;
border-bottom-right-radius: 5px;
border-bottom-left-radius: 5px;
width: 350px;
padding-top: 15px;
padding-left: 20px;
padding-bottom: 15px;
box-shadow: 1px 3px 1px #e7e7e7;
margin-left: auto;
margin-right: auto;
/**
* Gradient calculated from gradient calculator of
* http://gradients.glrzad.com/
*/
background-image: linear-gradient(bottom, rgb(242,245,250) 21%, rgb(242,245,250) 67%, rgb(242,245,255) 94%);
background-image: -o-linear-gradient(bottom, rgb(242,245,250) 21%, rgb(242,245,250) 67%, rgb(242,245,255) 94%);
background-image: -moz-linear-gradient(bottom, rgb(242,245,250) 21%, rgb(242,245,250) 67%, rgb(242,245,255) 94%);
background-image: -webkit-linear-gradient(bottom, rgb(242,245,250) 21%, rgb(242,245,250) 67%, rgb(242,245,255) 94%);
background-image: -ms-linear-gradient(bottom, rgb(242,245,250) 21%, rgb(242,245,250) 67%, rgb(242,245,255) 94%);
background-image: -webkit-gradient(
linear,
left bottom,
left top,
color-stop(0.21, rgb(242,245,250)),
color-stop(0.67, rgb(242,245,250)),
color-stop(0.94, rgb(242,245,255))
);
}
/**
* Okay, you caught me. It's a hack to make this look centered.
*
* TODO Fix this, can't figure out how to get this to center correctly.
* It's currently anchored to the fieldset and that's causing issues.
*/
.title-padding {
padding-left: 15px;
}
/**
* The username and password labels
*/
.labels {
color: #505050;
text-shadow: 2px 1px 3px rgba(200, 200, 200, 0.43);
padding-bottom: 5px;
padding-top: 10px;
}
/**
* Input fields so I can make it slightly larger than the default,
* and I can also pad anything trying to touch it on the right.
*/
.input-fields {
padding-right: 20px;
font-size: 130%;
}
/**
* This makes all the placeholder text italic. Nice trick I
* picked up from stack overflow:
* http://stackoverflow.com/questions/16291925/how-to-make-value-text-in-form-be-italic
*/
::-webkit-input-placeholder { font-style: italic; }
::-moz-placeholder { font-style: italic; }
:-ms-input-placeholder { font-style: italic; }
/**
* Very specific to the sign on button.
*/
.sign-in-button {
padding-right: 20px;
text-align: right;
}
/**
* Very specific to the "from website" link
*/
.from-text {
padding-top: 10px;
text-align: center;
}

View File

@@ -0,0 +1,8 @@
body {
padding: 50px;
font: 14px "Lucida Grande", Helvetica, Arial, sans-serif;
}
a {
color: #00B7FF;
}

View File

@@ -0,0 +1,238 @@
body {
color: #777;
}
.pure-img-responsive {
max-width: 100%;
height: auto;
}
/*
Add transition to containers so they can push in and out.
*/
#layout,
#menu,
.menu-link {
-webkit-transition: all 0.2s ease-out;
-moz-transition: all 0.2s ease-out;
-ms-transition: all 0.2s ease-out;
-o-transition: all 0.2s ease-out;
transition: all 0.2s ease-out;
}
/*
This is the parent `<div>` that contains the menu and the content area.
*/
#layout {
position: relative;
padding-left: 0;
}
#layout.active {
position: relative;
left: 150px;
}
#layout.active #menu {
left: 150px;
width: 150px;
}
#layout.active .menu-link {
left: 150px;
}
/*
The content `<div>` is where all your content goes.
*/
.content {
margin: 0;
padding: 0 2em;
max-width: 800px;
margin-bottom: 50px;
line-height: 1.6em;
}
.header {
margin: 0;
color: #333;
text-align: center;
padding: 2.5em 2em 0;
border-bottom: 1px solid #eee;
}
.header h1 {
margin: 0.2em 0;
font-size: 3em;
font-weight: 300;
}
.header h2 {
font-weight: 300;
color: #ccc;
padding: 0;
margin-top: 0;
}
.content-subhead {
margin: 50px 0 20px 0;
font-weight: 300;
color: #888;
}
/*
The `#menu` `<div>` is the parent `<div>` that contains the `.pure-menu` that
appears on the left side of the page.
*/
#menu {
margin-left: -150px; /* "#menu" width */
width: 150px;
position: fixed;
top: 0;
left: 0;
bottom: 0;
z-index: 1000; /* so the menu or its navicon stays above all content */
background: #191818;
overflow-y: auto;
-webkit-overflow-scrolling: touch;
}
/*
All anchors inside the menu should be styled like this.
*/
#menu a {
color: #999;
border: none;
padding: 0.6em 0 0.6em 0.6em;
}
/*
Remove all background/borders, since we are applying them to #menu.
*/
#menu .pure-menu,
#menu .pure-menu ul {
border: none;
background: transparent;
}
/*
Add that light border to separate items into groups.
*/
#menu .pure-menu ul,
#menu .pure-menu .menu-item-divided {
border-top: 1px solid #333;
}
/*
Change color of the anchor links on hover/focus.
*/
#menu .pure-menu li a:hover,
#menu .pure-menu li a:focus {
background: #333;
}
/*
This styles the selected menu item `<li>`.
*/
#menu .pure-menu-selected,
#menu .pure-menu-heading {
background: #1f8dd6;
}
/*
This styles a link within a selected menu item `<li>`.
*/
#menu .pure-menu-selected a {
color: #fff;
}
/*
This styles the menu heading.
*/
#menu .pure-menu-heading {
font-size: 110%;
color: #fff;
margin: 0;
}
/* -- Dynamic Button For Responsive Menu -------------------------------------*/
/*
The button to open/close the Menu is custom-made and not part of Pure. Here's
how it works:
*/
/*
`.menu-link` represents the responsive menu toggle that shows/hides on
small screens.
*/
.menu-link {
position: fixed;
display: block; /* show this only on small screens */
top: 0;
left: 0; /* "#menu width" */
background: #000;
background: rgba(0,0,0,0.7);
font-size: 10px; /* change this value to increase/decrease button size */
z-index: 10;
width: 2em;
height: auto;
padding: 2.1em 1.6em;
}
.menu-link:hover,
.menu-link:focus {
background: #000;
}
.menu-link span {
position: relative;
display: block;
}
.menu-link span,
.menu-link span:before,
.menu-link span:after {
background-color: #fff;
width: 100%;
height: 0.2em;
}
.menu-link span:before,
.menu-link span:after {
position: absolute;
margin-top: -0.6em;
content: " ";
}
.menu-link span:after {
margin-top: 0.6em;
}
/* -- Responsive Styles (Media Queries) ------------------------------------- */
/*
Hides the menu at `48em`, but modify this based on your app's needs.
*/
@media (min-width: 48em) {
.header,
.content {
padding-left: 2em;
padding-right: 2em;
}
#layout {
padding-left: 150px; /* left col width "#menu" */
left: 0;
}
#menu {
left: 150px;
}
.menu-link {
position: fixed;
left: 150px;
display: none;
}
#layout.active .menu-link {
left: 150px;
}
}