179 lines
4.7 KiB
PHP
179 lines
4.7 KiB
PHP
<?php namespace OpenId\Models;
|
|
/**
|
|
* Copyright 2016 OpenStack Foundation
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
* you may not use this file except in compliance with the License.
|
|
* You may obtain a copy of the License at
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
**/
|
|
use OpenId\Exceptions\InvalidNonce;
|
|
use OpenId\Helpers\OpenIdErrorMessages;
|
|
use Utils\Model\AbstractIdentifier;
|
|
use Zend\Math\Rand;
|
|
|
|
/**
|
|
* Class OpenIdNonce
|
|
* @package OpenId\Models
|
|
*/
|
|
final class OpenIdNonce extends AbstractIdentifier
|
|
{
|
|
const NonceRegexFormat = '/(\d{4})-(\d\d)-(\d\d)T(\d\d):(\d\d):(\d\d)Z(.*)/';
|
|
const NonceTimeFormat = '%Y-%m-%dT%H:%M:%SZ';
|
|
|
|
/**
|
|
* @var string
|
|
*/
|
|
private $timestamp;
|
|
/**
|
|
* @var string
|
|
*/
|
|
private $unique_id;
|
|
|
|
|
|
/**
|
|
* @param int $len
|
|
* @param int $lifetime
|
|
*/
|
|
public function __construct($len, $lifetime = 0)
|
|
{
|
|
parent::__construct($len, $lifetime);
|
|
}
|
|
|
|
/**
|
|
* @return string
|
|
*/
|
|
public function getRawFormat()
|
|
{
|
|
return $this->value;
|
|
}
|
|
|
|
/**
|
|
* @return string
|
|
*/
|
|
public function getTimestamp()
|
|
{
|
|
return $this->timestamp;
|
|
}
|
|
|
|
/**
|
|
* @return string
|
|
*/
|
|
public function getUniqueId()
|
|
{
|
|
return $this->unique_id;
|
|
}
|
|
|
|
/**
|
|
* The time-stamp MAY be used to reject responses that are too far away from the current time,
|
|
* limiting the amount of time that nonces must be stored to prevent attacks.
|
|
* The acceptable range is out of the scope of this specification.
|
|
* A larger range requires storing more nonces for a longer time.
|
|
* A shorter range increases the chance that clock-skew and transaction time will cause
|
|
* a spurious rejection.
|
|
* @param $allowed_skew
|
|
* @return bool
|
|
*/
|
|
public function isValid($allowed_skew)
|
|
{
|
|
$now = time();
|
|
// Time after which we should not use the nonce
|
|
$past = $now - $allowed_skew;
|
|
// Time that is too far in the future for us to allow
|
|
$future = $now + $allowed_skew;
|
|
|
|
// the stamp is not too far in the future and is not too far
|
|
// in the past
|
|
return (($past <= $this->timestamp) && ($this->timestamp <= $future));
|
|
}
|
|
|
|
/**
|
|
* @param string $value
|
|
* @return $this
|
|
* @throws InvalidNonce
|
|
*/
|
|
public function setValue($value)
|
|
{
|
|
// Extract a timestamp from the given nonce string
|
|
$result = preg_match(self::NonceRegexFormat, $value, $matches);
|
|
if ($result != 1 || count($matches) != 8) {
|
|
throw new InvalidNonce(sprintf(OpenIdErrorMessages::InvalidNonceFormatMessage, $value));
|
|
}
|
|
|
|
list($unused,
|
|
$tm_year,
|
|
$tm_mon,
|
|
$tm_mday,
|
|
$tm_hour,
|
|
$tm_min,
|
|
$tm_sec,
|
|
$unique_id) = $matches;
|
|
|
|
$timestamp = @gmmktime($tm_hour, $tm_min, $tm_sec, $tm_mon, $tm_mday, $tm_year);
|
|
|
|
if ($timestamp == false || $timestamp < 0) {
|
|
throw new InvalidNonce(sprintf(OpenIdErrorMessages::InvalidNonceTimestampMessage, $value));
|
|
}
|
|
|
|
$this->timestamp = $timestamp;
|
|
$this->unique_id = $unique_id;
|
|
$this->len = strlen($value);
|
|
|
|
return parent::setValue($value);
|
|
}
|
|
|
|
/**
|
|
* @param string $value
|
|
* @return OpenIdNonce
|
|
* @throws InvalidNonce
|
|
*/
|
|
static public function fromValue($value)
|
|
{
|
|
$nonce = new OpenIdNonce(255);
|
|
|
|
return $nonce->setValue($value);
|
|
}
|
|
|
|
/**
|
|
* @return string
|
|
*/
|
|
public function getType():string
|
|
{
|
|
return 'nonce';
|
|
}
|
|
|
|
/**
|
|
* @inheritDoc
|
|
*/
|
|
public function toArray(): array
|
|
{
|
|
return [];
|
|
}
|
|
|
|
/*
|
|
* MAY contain additional ASCII characters in the range 33-126 inclusive (printable non-whitespace characters), as necessary to make each response unique
|
|
*/
|
|
const NoncePopulation = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
|
|
/**
|
|
* Nonce Salt Length
|
|
*/
|
|
const NonceSaltLength = 32;
|
|
|
|
/**
|
|
* @return string
|
|
* @throws InvalidNonce
|
|
*/
|
|
public function generateValue(): string
|
|
{
|
|
$salt = Rand::getString(self::NonceSaltLength, self::NoncePopulation);
|
|
$date_part = false;
|
|
do{ $date_part = gmdate('Y-m-d\TH:i:s\Z'); } while($date_part === false);
|
|
$raw_nonce = $date_part. $salt;
|
|
$this->setValue($raw_nonce);
|
|
return $this->value;
|
|
}
|
|
} |