[smarcet] - Refs #4578 - OpenId - Server Core Logic - Authentication Workflow

This commit is contained in:
smarcet 2013-10-22 01:14:55 -03:00
parent 122ea0c0a5
commit f1ad337e3a
22 changed files with 1165 additions and 255 deletions

File diff suppressed because it is too large Load Diff

View File

@ -23,10 +23,14 @@ class DiscoveryController extends BaseController {
* @return xrds document on response
*/
public function idp(){
$value = Request::header('Content-Type');
if($value == XRDSDocumentBuilder::ContentType){
//This field contains a semicolon-separated list of representation schemes
//which will be accepted in the response to this request.
$accept = Request::header('Accept');
$accept_values = explode(",",$accept);
if(in_array(XRDSDocumentBuilder::ContentType,$accept_values))
{
$response = Response::make($this->openid_protocol->getXRDSDiscovery(), 200);
$response->header('Content-Type', "application/xrds+xml");
$response->header('Content-Type', "application/xrds+xml; charset=UTF-8");
}
else{
$response = View::make("home");

View File

@ -3,8 +3,11 @@ use openid\XRDS\XRDSDocumentBuilder;
class HomeController extends BaseController {
public function index(){
$value = Request::header('Content-Type');
if($value == XRDSDocumentBuilder::ContentType)
//This field contains a semicolon-separated list of representation schemes
//which will be accepted in the response to this request.
$accept = Request::header('Accept');
$accept_values = explode(",",$accept);
if(in_array(XRDSDocumentBuilder::ContentType,$accept_values))
return Redirect::action('DiscoveryController@idp');
return View::make("home");
}

View File

@ -44,6 +44,8 @@ Route::filter('auth.basic', function()
return Auth::basic();
});
/*
|--------------------------------------------------------------------------
| Guest Filter

View File

@ -38,7 +38,7 @@ class AuthService implements IAuthService {
*/
public function Login($username, $password)
{
return Auth::attempt(array('username' => $username, 'password' => $password), true);
return Auth::attempt(array('username' => $username, 'password' => $password), false);
}
public function logout(){
@ -50,8 +50,11 @@ class AuthService implements IAuthService {
*/
public function getUserAuthorizationResponse()
{
if(Session::has("openid.authorization.response"))
return Session::get("openid.authorization.response");
if(Session::has("openid.authorization.response")){
$value= Session::get("openid.authorization.response");
Session::remove('openid.authorization.response');
return $value;
}
return IAuthService::AuthorizationResponse_None;
}

View File

@ -117,14 +117,16 @@ class OpenIdProtocol implements IOpenIdProtocol {
}
public function getXRDSDiscovery(){
$active_extensions = $this->server_extension_repository->GetAllExtensions();
$server_extension_service = \App::make("openid\\services\\IServerExtensionsService");
$server_config_service = \App::make("openid\\services\\IServerConfigurationService");
$active_extensions = $server_extension_service->getAllActiveExtensions();
$extensions = array();
foreach($active_extensions as $ext){
array_push($extensions,$ext->namespace);
array_push($extensions,$ext->getNamespace());
}
$services = array();
array_push($services, new XRDSService(0,self::OPIdentifierType,$this->server_configuration->getOPEndpointURL(),$extensions));
array_push($services, new XRDSService(0,self::OPIdentifierType,$server_config_service->getOPEndpointURL(),$extensions));
$builder = new XRDSDocumentBuilder($services);
$xrds = $builder->render();
return $xrds;

View File

@ -23,17 +23,8 @@ class XRDSDocumentBuilder {
public function render(){
$XRDNamespace = self::XRDNamespace;
$XRDSNamespace = self::XRDSNamespace;
$header = <<< XRDS
<?xml version="1.0" encoding="UTF-8"?>
<xrds:XRDS
xmlns:xrds="{$XRDSNamespace}"
xmlns="{$XRDNamespace}">
<XRD>
XRDS;
$footer = <<< XRDS
</XRD>
</xrds:XRDS>
XRDS;
$header = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<xrds:XRDS xmlns:xrds=\"{$XRDSNamespace}\" xmlns=\"{$XRDNamespace}\">\n<XRD>\n";
$footer = "</XRD>\n</xrds:XRDS>";
$xrds = $header;
foreach($this->elements as $service){
$xrds .= $service->render();

View File

@ -29,21 +29,14 @@ class XRDSService {
}
public function render(){
$local_id =empty($this->local_id)?"":"<LocalID>{$this->local_id}</LocalID>";
$local_id =empty($this->local_id)?"":"<LocalID>{$this->local_id}</LocalID>\n";
$extensions ="";
foreach($this->extensions as $extension){
$extensions.="<Type>{$extension}</Type>";
$extensions.="<Type>{$extension}</Type>\n";
}
$element = <<< SERVICE
<Service priority="{$this->priority}">
<Type>{$this->type}</Type>
{$extensions}
<URI>{$this->uri}</URI>
{$local_id}
</Service>
SERVICE;
$element ="<Service priority=\"{$this->priority}\">\n<Type>{$this->type}</Type>\n{$extensions}<URI>{$this->uri}</URI>\n{$local_id}</Service>\n";
return $element;
}

View File

@ -20,9 +20,13 @@ abstract class OpenIdExtension {
protected $description;
public function __construct($name,$namespace,$description){
$this->namespace=$namespace;
$this->name=$name;
$this->description = $description;
$this->namespace = $namespace;
$this->name = $name;
$this->description = $description;
}
public function getNamespace(){
return $this->namespace;
}
/**

View File

@ -18,6 +18,7 @@ use openid\responses\contexts\ResponseContext;
use openid\responses\OpenIdResponse;
use openid\services\Registry;
use openid\OpenIdMessage;
use openid\exceptions\InvalidOpenIdMessageException;
class OpenIdAXRequest extends OpenIdRequest
{
@ -50,7 +51,7 @@ class OpenIdAXRequest extends OpenIdRequest
)
throw new InvalidOpenIdMessageException("AX: not set or invalid mode mode");
if (isset($this->message[OpenIdProtocol::OpenIdPrefix . "_" . OpenIdAXExtension::Prefix . "_" . OpenIdAXExtension::RequiredAttributes]))
if (!isset($this->message[OpenIdProtocol::OpenIdPrefix . "_" . OpenIdAXExtension::Prefix . "_" . OpenIdAXExtension::RequiredAttributes]))
throw new InvalidOpenIdMessageException("AX: not set required attributes!");
$attributes = $this->message[OpenIdProtocol::OpenIdPrefix . "_" . OpenIdAXExtension::Prefix . "_" . OpenIdAXExtension::RequiredAttributes];
@ -58,13 +59,14 @@ class OpenIdAXRequest extends OpenIdRequest
foreach ($attributes as $attr) {
$attr = trim($attr);
if (!isset(OpenIdAXExtension::$available_properties[$attr]))
throw new InvalidOpenIdMessageException(sprintf("AX: invalid attribute requested %s", $attr));
if (!isset($this->message[OpenIdProtocol::OpenIdPrefix . "_" . self::Prefix . "_" . self::Type . "_" . $attr]))
//throw new InvalidOpenIdMessageException(sprintf("AX: invalid attribute requested %s", $attr));
continue;
if (!isset($this->message[OpenIdProtocol::OpenIdPrefix . "_" . OpenIdAXExtension::Prefix . "_" . OpenIdAXExtension::Type . "_" . $attr]))
throw new InvalidOpenIdMessageException(sprintf("AX: invalid ns for attribute %s", $attr));
$ns = $this->message[OpenIdProtocol::OpenIdPrefix . "_" . self::Prefix . "_" . self::Type . "_" . $attr];
$ns = $this->message[OpenIdProtocol::OpenIdPrefix . "_" . OpenIdAXExtension::Prefix . "_" . OpenIdAXExtension::Type . "_" . $attr];
if ($ns != OpenIdAXExtension::$available_properties[$attr])
throw new InvalidOpenIdMessageException(sprintf("AX: invalid ns for attribute %s", $attr));
array_push($this->$attributes, $attr);
array_push($this->attributes, $attr);
}
return true;
}
@ -101,7 +103,7 @@ class OpenIdAXExtension extends OpenIdExtension
self::$available_properties[OpenIdAXExtension::Country] = "http://axschema.org/contact/country/home";
self::$available_properties[OpenIdAXExtension::Email] = "http://axschema.org/contact/email";
self::$available_properties[OpenIdAXExtension::FirstMame] = "http://axschema.org/namePerson/first";
self::$available_properties[OpenIdAXExtension::LastName] = "http://axschema.org/pref/language";
self::$available_properties[OpenIdAXExtension::LastName] = "http://axschema.org/namePerson/last";
self::$available_properties[OpenIdAXExtension::Language] = "http://axschema.org/pref/language";
}

View File

@ -23,7 +23,7 @@ use openid\responses\OpenIdNonImmediateNegativeAssertion;
use openid\responses\OpenIdImmediateNegativeAssertion;
use openid\services\ITrustedSitesService;
use openid\responses\OpenIdIndirectResponse;
use openid\exceptions\OpenIdIndirectGenericErrorResponse;
use openid\responses\OpenIdIndirectGenericErrorResponse;
use openid\helpers\OpenIdErrorMessages;
use openid\helpers\OpenIdCryptoHelper;
use openid\model\IAssociation;
@ -111,9 +111,12 @@ class OpenIdAuthenticationRequestHandler extends OpenIdMessageHandler
protected function InternalHandle(OpenIdMessage $message)
{
$request = null;
try
{
$request = new OpenIdAuthenticationRequest($message);
if(!$request->IsValid())
throw new InvalidOpenIdMessageException("OpenIdAuthenticationRequest is Invalid!");
$extensions = $this->server_extensions_service->getAllActiveExtensions();
$context = new RequestContext;
$mode = $request->getMode();
@ -168,15 +171,22 @@ class OpenIdAuthenticationRequestHandler extends OpenIdMessageHandler
return $this->doAssertion($request, $extensions);
break;
case IAuthService::AuthorizationResponse_DenyOnce:
return new OpenIdNonImmediateNegativeAssertion;
break;
case IAuthService::AuthorizationResponse_DenyForever:
{
$response = new OpenIdNonImmediateNegativeAssertion;
$response->setReturnTo($request->getReturnTo());
return $response;
}
break;
case IAuthService::AuthorizationResponse_DenyForever:{
$this->trusted_sites_service->addTrustedSite($currentUser, $request->getTrustedRoot(), IAuthService::AuthorizationResponse_DenyForever);
return new OpenIdNonImmediateNegativeAssertion;
break;
$response = new OpenIdNonImmediateNegativeAssertion;
$response->setReturnTo($request->getReturnTo());
return $response;
}
break;
default:
throw new \Exception("Invalid Authorization response!");
break;
throw new \Exception("Invalid Authorization response!");
break;
}
}
}
@ -206,7 +216,15 @@ class OpenIdAuthenticationRequestHandler extends OpenIdMessageHandler
}
}
catch (InvalidOpenIdMessageException $ex) {
return new OpenIdIndirectGenericErrorResponse($ex->getMessage());
$response = new OpenIdIndirectGenericErrorResponse($ex->getMessage());
if(!is_null($request)){
$return_to = $request->getReturnTo();
if(!empty($return_to))
$response->setReturnTo($return_to);
}
return $response ;
}
}

View File

@ -9,8 +9,64 @@
namespace openid\helpers;
define('OpenIdUriHelper_TLDs',
'/\.(ac|ad|ae|aero|af|ag|ai|al|am|an|ao|aq|ar|arpa|as|asia' .
'|at|au|aw|ax|az|ba|bb|bd|be|bf|bg|bh|bi|biz|bj|bm|bn|bo|br' .
'|bs|bt|bv|bw|by|bz|ca|cat|cc|cd|cf|cg|ch|ci|ck|cl|cm|cn|co' .
'|com|coop|cr|cu|cv|cx|cy|cz|de|dj|dk|dm|do|dz|ec|edu|ee|eg' .
'|er|es|et|eu|fi|fj|fk|fm|fo|fr|ga|gb|gd|ge|gf|gg|gh|gi|gl' .
'|gm|gn|gov|gp|gq|gr|gs|gt|gu|gw|gy|hk|hm|hn|hr|ht|hu|id|ie' .
'|il|im|in|info|int|io|iq|ir|is|it|je|jm|jo|jobs|jp|ke|kg|kh' .
'|ki|km|kn|kp|kr|kw|ky|kz|la|lb|lc|li|lk|lr|ls|lt|lu|lv|ly' .
'|ma|mc|md|me|mg|mh|mil|mk|ml|mm|mn|mo|mobi|mp|mq|mr|ms|mt' .
'|mu|museum|mv|mw|mx|my|mz|na|name|nc|ne|net|nf|ng|ni|nl|no' .
'|np|nr|nu|nz|om|org|pa|pe|pf|pg|ph|pk|pl|pm|pn|pr|pro|ps|pt' .
'|pw|py|qa|re|ro|rs|ru|rw|sa|sb|sc|sd|se|sg|sh|si|sj|sk|sl' .
'|sm|sn|so|sr|st|su|sv|sy|sz|tc|td|tel|tf|tg|th|tj|tk|tl|tm' .
'|tn|to|tp|tr|travel|tt|tv|tw|tz|ua|ug|uk|us|uy|uz|va|vc|ve' .
'|vg|vi|vn|vu|wf|ws|xn--0zwm56d|xn--11b5bs3a9aj6g' .
'|xn--80akhbyknj4f|xn--9t4b11yi5a|xn--deba0ad|xn--g6w251d' .
'|xn--hgbk6aj7f53bba|xn--hlcj6aya9esc7a|xn--jxalpdlp' .
'|xn--kgbechtv|xn--zckzah|ye|yt|yu|za|zm|zw)\.?$/');
class OpenIdUriHelper {
define('OpenIdUriHelper_HostSegmentRe', "/^(?:[-a-zA-Z0-9!$&'\\(\\)\\*+,;=._~]|%[a-zA-Z0-9]{2})*$/");
class OpenIdUriHelper
{
const AuthorityPattern = "/^([^@]*@)?([^:]*)(:.*)?/";
const URIPattern = "&^(([^:/?#]+):)?(//([^/?#]*))?([^?#]*)(\?([^#]*))?(#(.*))?&";
const EncodedPattern = "/%([0-9A-Fa-f]{2})/";
const URLIllegalCharRE = "/([^-A-Za-z0-9:\/\?#\[\]@\!\$&'\(\)\*\+,;=\._~\%])/";
public static function getUnreserved()
{
$_unreserved = array();
for ($i = 0; $i < 256; $i++) {
$_unreserved[$i] = false;
}
for ($i = ord('A'); $i <= ord('Z'); $i++) {
$_unreserved[$i] = true;
}
for ($i = ord('0'); $i <= ord('9'); $i++) {
$_unreserved[$i] = true;
}
for ($i = ord('a'); $i <= ord('z'); $i++) {
$_unreserved[$i] = true;
}
$_unreserved[ord('-')] = true;
$_unreserved[ord('.')] = true;
$_unreserved[ord('_')] = true;
$_unreserved[ord('~')] = true;
return $_unreserved;
}
/**
* Returns an absolute URL for the given one
@ -18,7 +74,7 @@ class OpenIdUriHelper {
* @param string $url absilute or relative URL
* @return string
*/
static public function absoluteUrl($url)
public static function absoluteUrl($url)
{
if (empty($url)) {
return Zend_OpenId::selfUrl();
@ -61,7 +117,7 @@ class OpenIdUriHelper {
* @param string &$id url to be normalized
* @return bool
*/
static public function normalizeUrl(&$id)
public static function normalizeUrl(&$id)
{
// RFC 3986, 6.2.2. Syntax-Based Normalization
@ -101,7 +157,8 @@ class OpenIdUriHelper {
$ch == '-' ||
$ch == '.' ||
$ch == '_' ||
$ch == '~') {
$ch == '~'
) {
$res .= $ch;
} else {
$res .= '%';
@ -201,14 +258,420 @@ class OpenIdUriHelper {
return true;
}
static public function checkRealmWildcard($root,$realm){
$n = strpos($realm, '://*.');
if ($n != false) {
$regex = '/^'. preg_quote(substr($realm, 0, $n+3), '/'). '[A-Za-z1-9_\.]+?'. preg_quote(substr($realm, $n+4), '/'). '/';
if (preg_match($regex, $root)) {
return true;
private static function startswith($s, $stuff)
{
return strpos($s, $stuff) === 0;
}
private static function remove_dot_segments($path)
{
$result_segments = array();
while ($path) {
if (self::startswith($path, '../')) {
$path = substr($path, 3);
} else if (self::startswith($path, './')) {
$path = substr($path, 2);
} else if (self::startswith($path, '/./')) {
$path = substr($path, 2);
} else if ($path == '/.') {
$path = '/';
} else if (self::startswith($path, '/../')) {
$path = substr($path, 3);
if ($result_segments) {
array_pop($result_segments);
}
} else if ($path == '/..') {
$path = '/';
if ($result_segments) {
array_pop($result_segments);
}
} else if (($path == '..') ||
($path == '.')
) {
$path = '';
} else {
$i = 0;
if ($path[0] == '/') {
$i = 1;
}
$i = strpos($path, '/', $i);
if ($i === false) {
$i = strlen($path);
}
$result_segments[] = substr($path, 0, $i);
$path = substr($path, $i);
}
}
return false;
return implode('', $result_segments);
}
private static function urinorm($uri)
{
$uri_matches = array();
preg_match(self::URIPattern, $uri, $uri_matches);
if (count($uri_matches) < 9) {
for ($i = count($uri_matches); $i <= 9; $i++) {
$uri_matches[] = '';
}
}
$illegal_matches = array();
preg_match(self::URLIllegalCharRE,
$uri, $illegal_matches);
if ($illegal_matches) {
return null;
}
$scheme = $uri_matches[2];
if ($scheme) {
$scheme = strtolower($scheme);
}
$scheme = $uri_matches[2];
if ($scheme === '') {
// No scheme specified
return null;
}
$scheme = strtolower($scheme);
if (!in_array($scheme, array('http', 'https'))) {
// Not an absolute HTTP or HTTPS URI
return null;
}
$authority = $uri_matches[4];
if ($authority === '') {
// Not an absolute URI
return null;
}
$authority_matches = array();
preg_match(self::AuthorityPattern,
$authority, $authority_matches);
if (count($authority_matches) === 0) {
// URI does not have a valid authority
return null;
}
if (count($authority_matches) < 4) {
for ($i = count($authority_matches); $i <= 4; $i++) {
$authority_matches[] = '';
}
}
list($_whole, $userinfo, $host, $port) = $authority_matches;
if ($userinfo === null) {
$userinfo = '';
}
if (strpos($host, '%') !== -1) {
$host = strtolower($host);
$host = preg_replace_callback(
self::EncodedPattern,
function ($mo) {
return chr(intval($mo[1], 16));
}, $host);
// NO IDNA.
// $host = unicode($host, 'utf-8').encode('idna');
} else {
$host = strtolower($host);
}
if ($port) {
if (($port == ':') ||
($scheme == 'http' && $port == ':80') ||
($scheme == 'https' && $port == ':443')
) {
$port = '';
}
} else {
$port = '';
}
$authority = $userinfo . $host . $port;
$path = $uri_matches[5];
$path = preg_replace_callback(
self::EncodedPattern,
function ($mo) {
$_unreserved = OpenIdUriHelper::getUnreserved();
$i = intval($mo[1], 16);
if ($_unreserved[$i]) {
return chr($i);
} else {
return strtoupper($mo[0]);
}
return $mo[0];
}, $path);
$path = self::remove_dot_segments($path);
if (!$path) {
$path = '/';
}
$query = $uri_matches[6];
if ($query === null) {
$query = '';
}
$fragment = $uri_matches[8];
if ($fragment === null) {
$fragment = '';
}
return $scheme . '://' . $authority . $path . $query . $fragment;
}
private static function _parse($trust_root)
{
$trust_root = self::urinorm($trust_root);
if ($trust_root === null) {
return false;
}
if (preg_match("/:\/\/[^:]+(:\d+){2,}(\/|$)/", $trust_root)) {
return false;
}
$parts = @parse_url($trust_root);
if ($parts === false) {
return false;
}
$required_parts = array('scheme', 'host');
$forbidden_parts = array('user', 'pass', 'fragment');
$keys = array_keys($parts);
if (array_intersect($keys, $required_parts) != $required_parts) {
return false;
}
if (array_intersect($keys, $forbidden_parts) != array()) {
return false;
}
if (!preg_match(OpenIdUriHelper_HostSegmentRe, $parts['host'])) {
return false;
}
$scheme = strtolower($parts['scheme']);
$allowed_schemes = array('http', 'https');
if (!in_array($scheme, $allowed_schemes)) {
return false;
}
$parts['scheme'] = $scheme;
$host = strtolower($parts['host']);
$hostparts = explode('*', $host);
switch (count($hostparts)) {
case 1:
$parts['wildcard'] = false;
break;
case 2:
if ($hostparts[0] ||
($hostparts[1] && substr($hostparts[1], 0, 1) != '.')
) {
return false;
}
$host = $hostparts[1];
$parts['wildcard'] = true;
break;
default:
return false;
}
if (strpos($host, ':') !== false) {
return false;
}
$parts['host'] = $host;
if (isset($parts['path'])) {
$path = strtolower($parts['path']);
if (substr($path, 0, 1) != '/') {
return false;
}
} else {
$path = '/';
}
$parts['path'] = $path;
if (!isset($parts['port'])) {
$parts['port'] = false;
}
$parts['unparsed'] = $trust_root;
return $parts;
}
/**
* Is this trust root sane?
*
* A trust root is sane if it is syntactically valid and it has a
* reasonable domain name. Specifically, the domain name must be
* more than one level below a standard TLD or more than two
* levels below a two-letter tld.
*
* For example, '*.com' is not a sane trust root, but '*.foo.com'
* is. '*.co.uk' is not sane, but '*.bbc.co.uk' is.
*
* This check is not always correct, but it attempts to err on the
* side of marking sane trust roots insane instead of marking
* insane trust roots sane. For example, 'kink.fm' is marked as
* insane even though it "should" (for some meaning of should) be
* marked sane.
*
* This function should be used when creating OpenID servers to
* alert the users of the server when a consumer attempts to get
* the user to accept a suspicious trust root.
*
* @static
* @param string $trust_root The trust root to check
* @return bool $sanity Whether the trust root looks OK
*/
private static function isSane($trust_root)
{
$parts = self::_parse($trust_root);
if ($parts === false) {
return false;
}
// Localhost is a special case
if ($parts['host'] == 'localhost') {
return true;
}
$host_parts = explode('.', $parts['host']);
if ($parts['wildcard']) {
// Remove the empty string from the beginning of the array
array_shift($host_parts);
}
if ($host_parts && !$host_parts[count($host_parts) - 1]) {
array_pop($host_parts);
}
if (!$host_parts) {
return false;
}
// Don't allow adjacent dots
if (in_array('', $host_parts, true)) {
return false;
}
// Get the top-level domain of the host. If it is not a valid TLD,
// it's not sane.
preg_match(OpenIdUriHelper_TLDs, $parts['host'], $matches);
if (!$matches) {
return false;
}
$tld = $matches[1];
if (count($host_parts) == 1) {
return false;
}
if ($parts['wildcard']) {
// It's a 2-letter tld with a short second to last segment
// so there needs to be more than two segments specified
// (e.g. *.co.uk is insane)
$second_level = $host_parts[count($host_parts) - 2];
if (strlen($tld) == 2 && strlen($second_level) <= 3) {
return count($host_parts) > 2;
}
}
return true;
}
/**
* Does this URL match the given trust root?
*
* Return whether the URL falls under the given trust root. This
* does not check whether the trust root is sane. If the URL or
* trust root do not parse, this function will return false.
*
* @param string $trust_root The trust root to match against
*
* @param string $url The URL to check
*
* @return bool $matches Whether the URL matches against the
* trust root
*/
public static function checkRealm($trust_root, $url)
{
if (!filter_var($url, FILTER_VALIDATE_URL)) return false;
if (!self::isSane($trust_root)) return false;
$trust_root_parsed = self::_parse($trust_root);
$url_parsed = self::_parse($url);
if (!$trust_root_parsed || !$url_parsed) {
return false;
}
// Check hosts matching
if ($url_parsed['wildcard']) {
return false;
}
if ($trust_root_parsed['wildcard']) {
$host_tail = $trust_root_parsed['host'];
$host = $url_parsed['host'];
if ($host_tail &&
substr($host, -(strlen($host_tail))) != $host_tail &&
substr($host_tail, 1) != $host
) {
return false;
}
} else {
if ($trust_root_parsed['host'] != $url_parsed['host']) {
return false;
}
}
// Check path and query matching
$base_path = $trust_root_parsed['path'];
$path = $url_parsed['path'];
if (!isset($trust_root_parsed['query'])) {
if ($base_path != $path) {
if (substr($path, 0, strlen($base_path)) != $base_path) {
return false;
}
if (substr($base_path, strlen($base_path) - 1, 1) != '/' &&
substr($path, strlen($base_path), 1) != '/'
) {
return false;
}
}
} else {
$base_query = $trust_root_parsed['query'];
$query = @$url_parsed['query'];
$qplus = substr($query, 0, strlen($base_query) + 1);
$bqplus = $base_query . '&';
if ($base_path != $path ||
($base_query != $query && $qplus != $bqplus)
) {
return false;
}
}
// The port and scheme need to match exactly
return ($trust_root_parsed['scheme'] == $url_parsed['scheme'] &&
$url_parsed['port'] === $trust_root_parsed['port']);
}
public static function checkReturnTo($return_to){
if (!filter_var($return_to, FILTER_VALIDATE_URL)) return false;
$url_parsed = self::_parse($return_to);
if (!$url_parsed) {
return false;
}
return true;
}
}

View File

@ -35,7 +35,8 @@ class OpenIdAuthenticationRequest extends OpenIdRequest{
}
public function getReturnTo(){
return isset($this->message[OpenIdProtocol::param(OpenIdProtocol::OpenIDProtocol_ReturnTo,"_")])?$this->message[OpenIdProtocol::param(OpenIdProtocol::OpenIDProtocol_ReturnTo,"_")]:null;
$return_to = isset($this->message[OpenIdProtocol::param(OpenIdProtocol::OpenIDProtocol_ReturnTo,"_")])?$this->message[OpenIdProtocol::param(OpenIdProtocol::OpenIDProtocol_ReturnTo,"_")]:null;
return (OpenIdUriHelper::checkReturnTo($return_to))?$return_to:"";
}
public function getRealm(){
@ -58,12 +59,14 @@ class OpenIdAuthenticationRequest extends OpenIdRequest{
}
public function IsValid(){
$return_to = $this->getReturnTo();
$return_to = $this->getReturnTo();
$claimed_id = $this->getClaimedId();
$identity = $this->getIdentity();
$mode = $this->getMode();
//todo: validate url(format-regex) - white list /black list?
$identity = $this->getIdentity();
$mode = $this->getMode();
$realm = $this->getRealm();
return !empty($return_to)
&& !empty($realm)
&& OpenIdUriHelper::checkRealm($realm,$return_to)
&& !empty($claimed_id) && $claimed_id == OpenIdProtocol::IdentifierSelectType
&& !empty($identity) && $identity == OpenIdProtocol::IdentifierSelectType
&& !empty($mode) && ($mode == OpenIdProtocol::ImmediateMode || $mode == OpenIdProtocol::SetupMode);

View File

@ -17,6 +17,8 @@ use openid\exceptions\InvalidKVFormat;
*/
class OpenIdDirectResponse extends OpenIdResponse {
const OpenIdDirectResponse="OpenIdDirectResponse";
const DirectResponseContentType ="text/plain";
public function __construct(){
@ -64,6 +66,6 @@ class OpenIdDirectResponse extends OpenIdResponse {
public function getType()
{
return "direct";
return self::OpenIdDirectResponse;
}
}

View File

@ -14,7 +14,7 @@ use openid\OpenIdProtocol;
class OpenIdIndirectGenericErrorResponse extends OpenIdIndirectResponse {
public function __construct($error,$contact,$reference){
public function __construct($error,$contact=null,$reference=null){
parent::__construct();
$this->setHttpCode(self::HttpErrorResponse);
$this[OpenIdProtocol::param(OpenIdProtocol::OpenIDProtocol_Error)] = $error;

View File

@ -14,6 +14,7 @@ use openid\responses\OpenIdResponse;
class OpenIdIndirectResponse extends OpenIdResponse {
const IndirectResponseContentType ="application/x-www-form-urlencoded";
const OpenIdIndirectResponse="OpenIdIndirectResponse";
public function __construct(){
// Successful Responses: A server receiving a valid request MUST send a
@ -47,7 +48,7 @@ class OpenIdIndirectResponse extends OpenIdResponse {
public function getType()
{
return "indirect";
return self::OpenIdIndirectResponse;
}
public function setReturnTo($return_to){

View File

@ -27,7 +27,7 @@ class Registry {
public function set($key, $value) {
if (isset($this->registry[$key])) {
throw new Exception("There is already an entry for key " . $key);
throw new \Exception("There is already an entry for key " . $key);
}
$this->registry[$key] = $value;
@ -35,7 +35,7 @@ class Registry {
public function get($key) {
if (!isset($this->registry[$key])) {
throw new Exception("There is no entry for key " . $key);
throw new \Exception("There is no entry for key " . $key);
}
return $this->registry[$key];

View File

@ -9,13 +9,32 @@
namespace openid\strategies;
use openid\responses\OpenIdResponse;
use openid\responses\OpenIdDirectResponse;
use openid\responses\OpenIdIndirectResponse;
use openid\services\Registry;
class OpenIdResponseStrategyFactoryMethod {
/**
* @param OpenIdResponse $response
* @return IOpenIdResponseStrategy
* @throws \Exception
*/
public static function buildStrategy(OpenIdResponse $response){
return null;
$type = $response->getType();
switch($type)
{
case OpenIdIndirectResponse::OpenIdIndirectResponse:
{
return Registry::getInstance()->get(OpenIdIndirectResponse::OpenIdIndirectResponse);
}
break;
case OpenIdDirectResponse::OpenIdDirectResponse:
{
return Registry::getInstance()->get(OpenIdIndirectResponse::OpenIdDirectResponse);
}
break;
default:
throw new \Exception("Invalid OpenId response Type");
break;
}
}
}

View File

@ -11,7 +11,8 @@ namespace services;
use openid\model\IAssociation;
use openid\services\IAssociationService;
use \OpenIdAssociation;
use \DateTime;
use \DateInterval;
class AssociationService implements IAssociationService{
/**
@ -20,8 +21,18 @@ class AssociationService implements IAssociationService{
*/
public function getAssociation($handle)
{
//todo: need to add expiration logic
return OpenIdAssociation::where('identifier','=',$handle)->first();
$assoc = OpenIdAssociation::where('identifier','=',$handle)->first();
if(!is_null($assoc)){
$issued_date = new DateTime($assoc->issued);
$life_time = $assoc->lifetime;
$issued_date->add(new DateInterval('PT'.$life_time.'S'));
$now = new DateTime(gmdate("Y-m-d H:i:s", time()));
if($now>$issued_date){
$this->deleteAssociation($handle);
$assoc = null;
}
}
return $assoc;
}
/**

View File

@ -7,7 +7,6 @@
* To change this template use File | Settings | File Templates.
*/
namespace strategies;
use openid\responses\OpenIdResponse;
use openid\strategies\IOpenIdResponseStrategy;
use \Response;

View File

@ -9,6 +9,7 @@
namespace strategies;
use openid\strategies\IOpenIdResponseStrategy;
use \Response;
use \Redirect;
class OpenIdIndirectResponseStrategy implements IOpenIdResponseStrategy {

View File

@ -7,13 +7,20 @@
* To change this template use File | Settings | File Templates.
*/
namespace strategies;
use Illuminate\Support\ServiceProvider;
use openid\responses\OpenIdIndirectResponse;
use openid\responses\OpenIdDirectResponse;
use openid\services\Registry;
class OpenIdResponseStrategyProvider extends ServiceProvider {
public function register()
{
$this->app->singleton('OpenIdDirectResponseStrategy','strategies\\OpenIdDirectResponseStrategy');
$this->app->singleton('OpenIdIndirectResponseStrategy','strategies\\OpenIdIndirectResponseStrategy');
$this->app->singleton(OpenIdDirectResponse::OpenIdDirectResponse,'strategies\\OpenIdDirectResponseStrategy');
$this->app->singleton(OpenIdIndirectResponse::OpenIdIndirectResponse,'strategies\\OpenIdIndirectResponseStrategy');
Registry::getInstance()->set(OpenIdDirectResponse::OpenIdDirectResponse, $this->app->make(OpenIdDirectResponse::OpenIdDirectResponse));
Registry::getInstance()->set(OpenIdIndirectResponse::OpenIdIndirectResponse, $this->app->make(OpenIdIndirectResponse::OpenIdIndirectResponse));
}
}