Skip to content
Snippets Groups Projects
Commit 89346aae authored by Andreas Åkre Solberg's avatar Andreas Åkre Solberg
Browse files

OAuth module now uses permanent SQLlite storage instead of flat files...

git-svn-id: https://simplesamlphp.googlecode.com/svn/trunk@1792 44740490-163a-0410-bde0-09ae8108e29a
parent afbfd0ef
No related branches found
No related tags found
No related merge requests found
Showing
with 514 additions and 125 deletions
......@@ -16,6 +16,9 @@ require_once($baseDir . '/lib/_autoload.php');
require_once(dirname(dirname(__FILE__)) . '/libextinc/OAuth.php');
// Needed in order to make session_start to be called before output is printed.
$session = SimpleSAML_Session::getInstance();
$baseurl = (isset($_SERVER['argv'][1]) ? $_SERVER['argv'][1] : 'https://foodle.feide.no/simplesaml');
$key = (isset($_SERVER['argv'][2]) ? $_SERVER['argv'][2] : 'key');
$secret = (isset($_SERVER['argv'][3]) ? $_SERVER['argv'][3] : 'secret');
......
......@@ -10,7 +10,15 @@ $config = array (
/* Enable the getUserInfo endpoint. Do not enable unless you know what you do.
* It may give external parties access to userInfo unless properly secured.
*/
'getUserInfo.enable' => FALSE,
'getUserInfo.enable' => TRUE,
'requestTokenDuration' => 60*30, // 30 minutes
'accessTokenDuration' => 60*60*24, // 24 hours
'nonceCache' => 60*60*24*14, // 14 days
// Tag to run storage cleanup script using the cron module...
'cron_tag' => 'hourly',
);
<?php
/**
* Hook to run a cron job.
*
* @param array &$croninfo Output
*/
function oauth_hook_cron(&$croninfo) {
assert('is_array($croninfo)');
assert('array_key_exists("summary", $croninfo)');
assert('array_key_exists("tag", $croninfo)');
$oauthconfig = SimpleSAML_Configuration::getOptionalConfig('module_statistics.php');
if (is_null($oauthconfig->getValue('cron_tag', 'hourly'))) return;
if ($oauthconfig->getValue('cron_tag', NULL) !== $croninfo['tag']) return;
try {
$store = new sspmod_core_Storage_SQLPermanentStorage('oauth');
$cleaned = $store->removeExpired();
# if ($cleaned > 0)
$croninfo['summary'][] = 'OAuth clean up. Removed ' . $cleaned . ' expired entries from OAuth storage.';
} catch (Exception $e) {
$message = 'OAuth clean up cron script failed: ' . $e->getMessage();
SimpleSAML_Logger::warning($message);
$croninfo['summary'][] = $message;
}
}
?>
\ No newline at end of file
<?php
/**
* Hook to add link to the frontpage.
*
* @param array &$links The links on the frontpage, split into sections.
*/
function oauth_hook_frontpage(&$links) {
assert('is_array($links)');
assert('array_key_exists("links", $links)');
$links['federation']['oauthregistry'] = array(
'href' => SimpleSAML_Module::getModuleURL('oauth/registry.php'),
'text' => array('en' => 'OAuth Consumer Registry'),
'shorttext' => array('en' => 'OAuth Registry'),
);
}
?>
\ No newline at end of file
......@@ -35,7 +35,7 @@ class sspmod_oauth_Consumer {
if(array_key_exists('error', $responseParsed))
throw new Exception('Error getting request token: ') . $responseParsed['error'];
# echo('<pre>'); print_r($response_req); exit;
$requestToken = $responseParsed['oauth_token'];
......@@ -66,6 +66,7 @@ class sspmod_oauth_Consumer {
throw new Exception('Error contacting request_token endpoint on the OAuth Provider');
}
SimpleSAML_Logger::info(' ==== RESPONSE: '. $response_acc);
parse_str($response_acc, $accessResponseParsed);
......
......@@ -11,90 +11,71 @@ require_once(dirname(dirname(__FILE__)) . '/libextinc/OAuth.php');
*/
class sspmod_oauth_OAuthStore extends OAuthDataStore {
private $path;
private $store;
private $config;
function __construct($path = '/tmp/oauth/') {
if (!file_exists($path)) {
mkdir($path);
}
if (!is_dir($path))
throw new Exception('OAuth Storage Path [' . $path . '] is not a valid directory');
$this->path = $path;
function __construct() {
$this->store = new sspmod_core_Storage_SQLPermanentStorage('oauth');
$this->config = SimpleSAML_Configuration::getOptionalConfig('module_oauth.php');
}
private function filename($key) {
return $this->path . sha1($key) . '.oauthstore';
}
private function exists($key) {
return file_exists($this->filename($key));
}
private function get($key) {
error_log( 'Getting :' . $key . ' : ' . ($this->exists($key) ? 'FOUND' : 'NOTFOUND'));
if (!$this->exists($key)) return NULL;
return unserialize(file_get_contents($this->filename($key)));
}
private function set($key, $value) {
error_log('Setting :' . $key . ' : ' . ($this->exists($key) ? 'FOUND' : 'NOTFOUND'));
file_put_contents($this->filename($key), serialize($value));
}
private function remove($key) {
unlink($this->filename($key));
}
public function authorize($requestToken, $data) {
$this->set('validated.request.' . $requestToken, $data);
# set($type, $key1, $key2, $value, $duration = NULL) {
$this->store->set('authorized', $requestToken, '', $data, $this->config->getValue('requestTokenDuration', 60*30) );
}
public function isAuthorized($requestToken) {
return $this->exists('validated.request.' . $requestToken);
SimpleSAML_Logger::info('OAuth isAuthorized(' . $requestToken . ')');
return $this->store->exists('authorized', $requestToken, '');
}
public function getAuthorizedData($token) {
return $this->get('validated.request.' . $token);
SimpleSAML_Logger::info('OAuth getAuthorizedData(' . $token . ')');
$data = $this->store->get('authorized', $token, '');
return $data['value'];
}
public function moveAuthorizedData($requestToken, $accessToken) {
SimpleSAML_Logger::info('OAuth moveAuthorizedData(' . $requestToken . ', ' . $accessToken . ')');
$this->authorize($accessToken, $this->getAuthorizedData($requestToken));
$this->remove('validated.request.' . $requestToken);
$this->store->remove('authorized', $requestToken, '');
}
private function tokenTag($tokenType = 'default', $token) {
return 'token.' . $token . '.' . $tokenType;
}
function lookup_consumer($consumer_key) {
if ($consumer_key == 'key') return new OAuthConsumer("key", "secret", NULL);
return NULL;
public function lookup_consumer($consumer_key) {
SimpleSAML_Logger::info('OAuth lookup_consumer(' . $consumer_key . ')');
if (! $this->store->exists('consumers', $consumer_key, '')) return NULL;
$consumer = $this->store->get('consumers', $consumer_key, '');
// SimpleSAML_Logger::info('OAuth consumer dump(' . var_export($consumer, TRUE) . ')');
return new OAuthConsumer($consumer['value']['key'], $consumer['value']['secret'], NULL);
}
function lookup_token($consumer, $tokenType = 'default', $token) {
return $this->get($this->tokenTag($tokenType, $token));
SimpleSAML_Logger::info('OAuth lookup_token(' . $consumer->key . ', ' . $tokenType. ',' . $token . ')');
$data = $this->store->get($tokenType, $token, $consumer->key);
if ($data == NULL) throw new Exception('Could not find token');
return $data['value'];
}
function lookup_nonce($consumer, $token, $nonce, $timestamp) {
$nonceTag = 'nonce.' . $consumer->key . '.' . $nonce;
if ($this->exists($nonceTag))
return TRUE;
$this->set($nonceTag, $timestamp);
SimpleSAML_Logger::info('OAuth lookup_nonce(' . $consumer . ', ' . $token. ',' . $nonce . ')');
if ($this->store->exists('nonce', $nonce, $consumer->key)) return TRUE;
$this->store->set('nonce', $nonce, $consumer->key, TRUE, $this->config->getValue('nonceCache', 60*60*24*14));
return FALSE;
}
function new_request_token($consumer) {
SimpleSAML_Logger::info('OAuth new_request_token(' . $consumer . ')');
$token = new OAuthToken(SimpleSAML_Utilities::generateID(), SimpleSAML_Utilities::generateID());
$this->set($this->tokenTag('request', $token->key), $token);
$this->store->set('request', $token->key, $consumer->key, $token, $this->config->getValue('requestTokenDuration', 60*30) );
return $token;
}
function new_access_token($token, $consumer) {
function new_access_token($requestToken, $consumer) {
SimpleSAML_Logger::info('OAuth new_access_token(' . $requestToken . ',' . $consumer . ')');
$token = new OAuthToken(SimpleSAML_Utilities::generateID(), SimpleSAML_Utilities::generateID());
$this->set($this->tokenTag('access', $token->key), $token);
// SimpleSAML_Logger::info('OAuth new_access_token(' . $requestToken . ',' . $consumer . ',' . $token . ')');
$this->store->set('access', $token->key, $consumer->key, $token, $this->config->getValue('accessTokenDuration', 60*60*24) );
return $token;
}
......
<?php
/**
* Editor for OAuth Client Registry
*
* @author Andreas Åkre Solberg <andreas@uninett.no>, UNINETT AS.
* @package simpleSAMLphp
* @version $Id$
*/
class sspmod_oauth_Registry {
protected function getStandardField($request, &$entry, $key) {
if (array_key_exists('field_' . $key, $request)) {
$entry[$key] = $request['field_' . $key];
} else {
if (isset($entry[$key])) unset($entry[$key]);
}
}
public function formToMeta($request, $entry = array(), $override = NULL) {
$this->getStandardField($request, $entry, 'name');
$this->getStandardField($request, $entry, 'description');
$this->getStandardField($request, $entry, 'key');
$this->getStandardField($request, $entry, 'secret');
if ($override) {
foreach($override AS $key => $value) {
$entry[$key] = $value;
}
}
return $entry;
}
protected function requireStandardField($request, $key) {
if (!array_key_exists('field_' . $key, $request))
throw new Exception('Required field [' . $key . '] was missing.');
if (empty($request['field_' . $key]))
throw new Exception('Required field [' . $key . '] was empty.');
}
public function checkForm($request) {
$this->requireStandardField($request, 'name');
$this->requireStandardField($request, 'description');
}
protected function header($name) {
return '<tr ><td>&nbsp;</td><td class="header">' . $name . '</td></tr>';
}
protected function readonlyDateField($metadata, $key, $name) {
$value = '<span style="color: #aaa">Not set</a>';
if (array_key_exists($key, $metadata))
$value = date('j. F Y, G:i', $metadata[$key]);
return '<tr>
<td class="name">' . $name . '</td>
<td class="data">' . $value . '</td></tr>';
}
protected function readonlyField($metadata, $key, $name) {
$value = '';
if (array_key_exists($key, $metadata))
$value = $metadata[$key];
return '<tr>
<td class="name">' . $name . '</td>
<td class="data">' . htmlspecialchars($value) . '</td></tr>';
}
protected function hiddenField($key, $value) {
return '<input type="hidden" name="' . $key . '" value="' . htmlspecialchars($value) . '" />';
}
protected function flattenLanguageField(&$metadata, $key) {
if (array_key_exists($key, $metadata)) {
if (is_array($metadata[$key])) {
if (isset($metadata[$key]['en'])) {
$metadata[$key] = $metadata[$key]['en'];
} else {
unset($metadata[$key]);
}
}
}
}
protected function standardField($metadata, $key, $name, $textarea = FALSE) {
$value = '';
if (array_key_exists($key, $metadata)) {
$value = htmlspecialchars($metadata[$key]);
}
if ($textarea) {
return '<tr><td class="name">' . $name . '</td><td class="data">
<textarea name="field_' . $key . '" rows="5" cols="50">' . $value . '</textarea></td></tr>';
} else {
return '<tr><td class="name">' . $name . '</td><td class="data">
<input type="text" size="60" name="field_' . $key . '" value="' . $value . '" /></td></tr>';
}
}
public function metaToForm($metadata) {
// $this->flattenLanguageField($metadata, 'name');
// $this->flattenLanguageField($metadata, 'description');
return '<form action="registry.edit.php" method="post">' .
'<div id="tabdiv">' .
'<ul>' .
'<li><a href="#basic">Name and descrition</a></li>' .
// '<li><a href="#saml">SAML 2.0</a></li>' .
// '<li><a href="#attributes">Attributes</a></li>' .
// '<li><a href="#orgs">Organizations</a></li>' .
// '<li><a href="#contacts">Contacts</a></li>' .
'</ul>' .
'<div id="basic"><table class="formtable">' .
$this->standardField($metadata, 'name', 'Name of client') .
$this->standardField($metadata, 'description', 'Description of client', TRUE) .
$this->readonlyField($metadata, 'owner', 'Owner') .
$this->readonlyField($metadata, 'key', 'Consumer Key') .
$this->readonlyField($metadata, 'secret', 'Consumer Secret') .
$this->hiddenField('field_key', $metadata['key']) .
$this->hiddenField('field_secret', $metadata['secret']) .
'</table></div>' .
// '<div id="saml"><table class="formtable">' .
// $this->standardField($metadata, 'AssertionConsumerService', 'AssertionConsumerService endpoint') .
// $this->standardField($metadata, 'SingleLogoutService', 'SingleLogoutService endpoint') .
// // $this->standardField($metadata, 'certFingerprint', 'Certificate Fingerprint') .
//
// '</table></div>' .
'</div>' .
'<input type="submit" name="submit" value="Save" style="margin-top: 5px" />' .
'</form>';
}
}
......@@ -206,7 +206,7 @@ class OAuthRequest {/*{{{*/
// next check for the auth header, we need to do some extra stuff
// if that is the case, namely suck in the parameters from GET or POST
// so that we can include them in the signature
if (@substr($request_headers['Authorization'], 0, 6) == "OAuth ") {
if (array_key_exists('Authorization', $request_headers) && substr($request_headers['Authorization'], 0, 6) == "OAuth ") {
$header_parameters = OAuthRequest::split_header($request_headers['Authorization']);
$parameters = array_merge($req_parameters, $header_parameters);
$req = new OAuthRequest($http_method, $http_url, $parameters);
......@@ -589,6 +589,16 @@ class OAuthServer {/*{{{*/
*/
private function get_token(&$request, $consumer, $token_type="access") {/*{{{*/
$token_field = @$request->get_parameter('oauth_token');
// SimpleSAML_Logger::info('request: ' . var_export($request, TRUE));
// SimpleSAML_Logger::info('token_type: ' . var_export($token_type, TRUE));
// SimpleSAML_Logger::info('token_field: ' . var_export($token_field, TRUE));
//
// $bt = SimpleSAML_Utilities::buildBacktrace(new Exception());
// foreach ($bt AS $t) {
// SimpleSAML_Logger::info(' ' . $t);
// }
$token = $this->data_store->lookup_token(
$consumer, $token_type, $token_field
);
......@@ -612,7 +622,7 @@ class OAuthServer {/*{{{*/
$signature_method = $this->get_signature_method($request);
$signature = $request->get_parameter('oauth_signature');
$signature = $request->get_parameter('oauth_signature');
$valid_sig = $signature_method->check_signature(
$request,
$consumer,
......@@ -678,74 +688,6 @@ class OAuthDataStore {/*{{{*/
}/*}}}*/
/* A very naive dbm-based oauth storage
*/
class SimpleOAuthDataStore extends OAuthDataStore {/*{{{*/
private $dbh;
function __construct($path = "oauth.gdbm") {/*{{{*/
$this->dbh = dba_popen($path, 'c', 'gdbm');
}/*}}}*/
function __destruct() {/*{{{*/
dba_close($this->dbh);
}/*}}}*/
function lookup_consumer($consumer_key) {/*{{{*/
$rv = dba_fetch("consumer_$consumer_key", $this->dbh);
if ($rv === FALSE) {
return NULL;
}
$obj = unserialize($rv);
if (!($obj instanceof OAuthConsumer)) {
return NULL;
}
return $obj;
}/*}}}*/
function lookup_token($consumer, $token_type, $token) {/*{{{*/
$rv = dba_fetch("${token_type}_${token}", $this->dbh);
if ($rv === FALSE) {
return NULL;
}
$obj = unserialize($rv);
if (!($obj instanceof OAuthToken)) {
return NULL;
}
return $obj;
}/*}}}*/
function lookup_nonce($consumer, $token, $nonce, $timestamp) {/*{{{*/
if (dba_exists("nonce_$nonce", $this->dbh)) {
return TRUE;
} else {
dba_insert("nonce_$nonce", "1", $this->dbh);
return FALSE;
}
}/*}}}*/
function new_token($consumer, $type="request") {/*{{{*/
$key = md5(time());
$secret = time() + time();
$token = new OAuthToken($key, md5(md5($secret)));
if (!dba_insert("${type}_$key", serialize($token), $this->dbh)) {
throw new OAuthException("doooom!");
}
return $token;
}/*}}}*/
function new_request_token($consumer) {/*{{{*/
return $this->new_token($consumer, "request");
}/*}}}*/
function new_access_token($token, $consumer) {/*{{{*/
$token = $this->new_token($consumer, 'access');
dba_delete("request_" . $token->key, $this->dbh);
return $token;
}/*}}}*/
}/*}}}*/
class OAuthUtil {/*{{{*/
public static function urlencode_rfc3986($input) {/*{{{*/
if (is_array($input)) {
......
<?php
$this->data['jquery'] = array('version' => '1.6', 'core' => TRUE, 'ui' => TRUE, 'css' => TRUE);
$this->data['head'] = '<link rel="stylesheet" type="text/css" href="/' . $this->data['baseurlpath'] . 'module.php/metaedit/resources/style.css" />' . "\n";
$this->data['head'] .= '<script type="text/javascript">
$(document).ready(function() {
$("#tabdiv").tabs();
});
</script>';
$this->includeAtTemplateBase('includes/header.php');
echo('<h1>OAuth Client</h1>');
echo($this->data['form']);
echo('<p style="float: right"><a href="registry.php">Return to entity listing <strong>without saving...</strong></a></p>');
$this->includeAtTemplateBase('includes/footer.php');
<?php
$this->data['jquery'] = array('version' => '1.6', 'core' => TRUE, 'ui' => TRUE, 'css' => TRUE);
$this->data['head'] = '<link rel="stylesheet" type="text/css" href="/' . $this->data['baseurlpath'] . 'module.php/oauth/resources/style.css" />' . "\n";
// $this->data['head'] .= '<script type="text/javascript">
// $(document).ready(function() {
// $("#tabdiv").tabs();
// });
// </script>';
$this->includeAtTemplateBase('includes/header.php');
echo('<h1>OAuth Client Registry</h1>');
echo('<p>Here you can register new OAuth Clients. You are successfully logged in as ' . $this->data['userid'] . '</p>');
echo('<h2>Your clients</h2>');
echo('<table class="metalist" style="width: 100%">');
$i = 0; $rows = array('odd', 'even');
foreach($this->data['entries']['mine'] AS $entryc ) {
$entry = $entryc['value'];
$i++;
echo('<tr class="' . $rows[$i % 2] . '">
<td>' . $entry['name'] . '</td>
<td><tt>' . $entry['key'] . '</tt></td>
<td>
<a href="registry.edit.php?editkey=' . urlencode($entry['key']) . '">edit</a>
<a href="registry.php?delete=' . urlencode($entry['key']) . '">delete</a>
</td></tr>');
}
if ($i == 0) {
echo('<tr><td colspan="3">No entries registered</td></tr>');
}
echo('</table>');
echo('<p><a href="registry.edit.php">Add new client</a></p>');
echo('<h2>Other clients</h2>');
echo('<table class="metalist" style="width: 100%">');
$i = 0; $rows = array('odd', 'even');
foreach($this->data['entries']['others'] AS $entryc ) {
$entry = $entryc['value'];
$i++;
echo('<tr class="' . $rows[$i % 2] . '">
<td>' . $entry['name'] . '</td>
<td><tt>' . $entry['key'] . '</tt></td>
<td>' . (isset($entry['owner']) ? $entry['owner'] : 'No owner') . '
</td></tr>');
}
if ($i == 0) {
echo('<tr><td colspan="3">No entries registered</td></tr>');
}
echo('</table>');
$this->includeAtTemplateBase('includes/footer.php');
<?php
$this->includeAtTemplateBase('includes/header.php');
echo('<h1>OAuth Client saved</h1>');
echo('<p><a href="registry.php">Go back to OAuth client listing</a></p>');
$this->includeAtTemplateBase('includes/footer.php');
......@@ -12,13 +12,18 @@ $server->add_signature_method($hmac_method);
$server->add_signature_method($plaintext_method);
$req = OAuthRequest::from_request();
$requestToken = $req->get_parameter('oauth_token');
if (!$store->isAuthorized($requestToken)) {
throw new Exception('Your request was not authorized. Request token [' . $requestToken . '] not found.');
}
$accessToken = $server->fetch_access_token($req);
$data = $store->moveAuthorizedData($requestToken, $accessToken->key);
......
<?php
/* Load simpleSAMLphp, configuration and metadata */
$config = SimpleSAML_Configuration::getInstance();
$session = SimpleSAML_Session::getInstance();
$oauthconfig = SimpleSAML_Configuration::getOptionalConfig('module_oauth.php');
$store = new sspmod_core_Storage_SQLPermanentStorage('oauth');
$authsource = $oauthconfig->getValue('auth', 'admin');
$useridattr = $oauthconfig->getValue('useridattr', 'user');
if ($session->isValid($authsource)) {
$attributes = $session->getAttributes();
// Check if userid exists
if (!isset($attributes[$useridattr]))
throw new Exception('User ID is missing');
$userid = $attributes[$useridattr][0];
} else {
SimpleSAML_Auth_Default::initLogin($authsource, SimpleSAML_Utilities::selfURL());
}
function requireOwnership($entry, $userid) {
if (!isset($entry['owner']))
throw new Exception('OAuth Consumer has no owner. Which means no one is granted access, not even you.');
if ($entry['owner'] !== $userid)
throw new Exception('OAuth Consumer has an owner that is not equal to your userid, hence you are not granted access.');
}
if (array_key_exists('editkey', $_REQUEST)) {
$entryc = $store->get('consumers', $_REQUEST['editkey'], '');
$entry = $entryc['value'];
requireOwnership($entry, $userid);
} else {
$entry = array(
'owner' => $userid,
'key' => SimpleSAML_Utilities::generateID(),
'secret' => SimpleSAML_Utilities::generateID(),
);
}
$editor = new sspmod_oauth_Registry();
if (isset($_POST['submit'])) {
$editor->checkForm($_POST);
$entry = $editor->formToMeta($_POST, array(), array('owner' => $userid));
requireOwnership($entry, $userid);
# echo('<pre>Created: '); print_r($entry); exit;
$store->set('consumers', $entry['key'], '', $entry);
$template = new SimpleSAML_XHTML_Template($config, 'oauth:registry.saved.php');
$template->data['entry'] = $entry;
$template->show();
exit;
}
$form = $editor->metaToForm($entry);
$template = new SimpleSAML_XHTML_Template($config, 'oauth:registry.edit.tpl.php');
$template->data['form'] = $form;
$template->show();
<?php
/* Load simpleSAMLphp, configuration and metadata */
$config = SimpleSAML_Configuration::getInstance();
$session = SimpleSAML_Session::getInstance();
$oauthconfig = SimpleSAML_Configuration::getOptionalConfig('module_oauth.php');
$store = new sspmod_core_Storage_SQLPermanentStorage('oauth');
$authsource = $oauthconfig->getValue('auth', 'admin');
$useridattr = $oauthconfig->getValue('useridattr', 'user');
if ($session->isValid($authsource)) {
$attributes = $session->getAttributes();
// Check if userid exists
if (!isset($attributes[$useridattr]))
throw new Exception('User ID is missing');
$userid = $attributes[$useridattr][0];
} else {
SimpleSAML_Auth_Default::initLogin($authsource, SimpleSAML_Utilities::selfURL());
}
function requireOwnership($entry, $userid) {
if (!isset($entry['owner']))
throw new Exception('OAuth Consumer has no owner. Which means no one is granted access, not even you.');
if ($entry['owner'] !== $userid)
throw new Exception('OAuth Consumer has an owner that is not equal to your userid, hence you are not granted access.');
}
if (isset($_REQUEST['delete'])) {
$entryc = $store->get('consumers', $_REQUEST['delete'], '');
$entry = $entryc['value'];
requireOwnership($entry, $userid);
$store->remove('consumers', $entry['key'], '');
}
$list = $store->getList('consumers');
$slist = array('mine' => array(), 'others' => array());
if (is_array($list))
foreach($list AS $listitem) {
if (array_key_exists('owner', $listitem['value'])) {
if ($listitem['value']['owner'] === $userid) {
$slist['mine'][] = $listitem; continue;
}
}
$slist['others'][] = $listitem;
}
// echo('<pre>'); print_r($slist); exit;
$template = new SimpleSAML_XHTML_Template($config, 'oauth:registry.list.php');
$template->data['entries'] = $slist;
$template->data['userid'] = $userid;
$template->show();
table.formtable {
width: 100%;
}
table.formtable tr td.name {
text-align: right;
vertical-align: top;
padding-right: .6em;
}
table.formtable tr td.value {
text-align: left;
padding: 0px;
}
table.formtable tr td.header {
padding-left: 5px;
padding-top: 8px;
font-weight: bold;
font-size: 110%;
}
table.formtable tr td input,table.formtable tr td textarea {
width: 90%;
border: 1px solid #bbb;
margin: 2px 5px;
padding: 2px 4px;
}
table.metalist {
border: 1px solid #aaa;
border-collapse: collapse;
}
table.metalist tr td {
padding: 2px 5px;
}
table.metalist tr.even td {
background: #e5e5e5;
}
\ No newline at end of file
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment