Skip to content
GitLab
Menu
Projects
Groups
Snippets
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Sign in
Toggle navigation
Menu
Open sidebar
project
drupal
Commits
882ef344
Commit
882ef344
authored
Aug 13, 2013
by
catch
Browse files
Issue
#2036351
by damiankloip, Xano, dawehner: Convert CSRF tokens to a service.
parent
fcb24f94
Changes
7
Hide whitespace changes
Inline
Side-by-side
core/core.services.yml
View file @
882ef344
...
...
@@ -369,6 +369,14 @@ services:
class
:
Drupal\Core\EventSubscriber\LegacyAccessSubscriber
tags
:
-
{
name
:
event_subscriber
}
private_key
:
class
:
Drupal\Core\PrivateKey
arguments
:
[
'
@state'
]
csrf_token
:
class
:
Drupal\Core\Access\CsrfTokenGenerator
arguments
:
[
'
@private_key'
]
calls
:
-
[
setRequest
,
[
'
@?request'
]]
access_manager
:
class
:
Drupal\Core\Access\AccessManager
calls
:
...
...
core/includes/common.inc
View file @
882ef344
...
...
@@ -3032,21 +3032,21 @@ function drupal_json_decode($var) {
/**
* Ensures the private key variable used to generate tokens is set.
*
* @return
* @return
string
* The private key.
*
* @see \Drupal\Core\Access\CsrfTokenManager
*
* @deprecated as of Drupal 8.0. Use the 'private_key' service instead.
*/
function
drupal_get_private_key
()
{
if
(
!
(
$key
=
Drupal
::
state
()
->
get
(
'system.private_key'
)))
{
$key
=
Crypt
::
randomStringHashed
(
55
);
Drupal
::
state
()
->
set
(
'system.private_key'
,
$key
);
}
return
$key
;
return
\
Drupal
::
service
(
'private_key'
)
->
get
();
}
/**
* Generates a token based on $value, the user session, and the private key.
*
* @param $value
* @param
string
$value
* An additional value to base the token on.
*
* @return string
...
...
@@ -3055,28 +3055,34 @@ function drupal_get_private_key() {
* 'drupal_private_key' configuration variable.
*
* @see drupal_get_hash_salt()
* @see \Drupal\Core\Access\CsrfTokenManager
*
* @deprecated as of Drupal 8.0. Use the csrf_token service instead.
*/
function
drupal_get_token
(
$value
=
''
)
{
return
Crypt
::
hmacBase64
(
$value
,
session_id
()
.
drupal_get_private_key
()
.
drupal_get_hash_salt
()
);
return
\
Drupal
::
csrfToken
()
->
get
(
$value
);
}
/**
* Validates a token based on $value, the user session, and the private key.
*
* @param $token
* @param
string
$token
* The token to be validated.
* @param $value
* @param
string
$value
* An additional value to base the token on.
* @param $skip_anonymous
* @param
bool
$skip_anonymous
* Set to true to skip token validation for anonymous users.
*
* @return
* @return
bool
* True for a valid token, false for an invalid token. When $skip_anonymous
* is true, the return value will always be true for anonymous users.
*
* @see \Drupal\Core\Access\CsrfTokenManager
*
* @deprecated as of Drupal 8.0. Use the csrf_token service instead.
*/
function
drupal_valid_token
(
$token
,
$value
=
''
,
$skip_anonymous
=
FALSE
)
{
global
$user
;
return
((
$skip_anonymous
&&
$user
->
id
()
==
0
)
||
(
$token
==
drupal_get_token
(
$value
)));
return
\
Drupal
::
csrfToken
()
->
validate
(
$token
,
$value
,
$skip_anonymous
);
}
/**
...
...
core/lib/Drupal.php
View file @
882ef344
...
...
@@ -391,4 +391,14 @@ public static function languageManager() {
return
static
::
$container
->
get
(
'language_manager'
);
}
/**
* Returns the CSRF token manager service.
*
* @return \Drupal\Core\Access\CsrfTokenGenerator
* The CSRF token manager.
*/
public
static
function
csrfToken
()
{
return
static
::
$container
->
get
(
'csrf_token'
);
}
}
core/lib/Drupal/Core/Access/CsrfTokenGenerator.php
0 → 100644
View file @
882ef344
<?php
/**
* @file
* Contains \Drupal\Core\Access\CsrfTokenGenerator.
*/
namespace
Drupal\Core\Access
;
use
Drupal\Component\Utility\Crypt
;
use
Drupal\Core\PrivateKey
;
use
Symfony\Component\HttpFoundation\Request
;
/**
* Generates and validates CSRF tokens.
*
* @see \Drupal\Tests\Core\Access\CsrfTokenGeneratorTest
*/
class
CsrfTokenGenerator
{
/**
* The private key service.
*
* @var \Drupal\Core\PrivateKey
*/
protected
$privateKey
;
/**
* The current request object.
*
* @var \Symfony\Component\HttpFoundation\Request
*/
protected
$request
;
/**
* Constructs the token generator.
*
* @param \Drupal\Core\PrivateKey $private_key
* The private key service.
*/
public
function
__construct
(
PrivateKey
$private_key
)
{
$this
->
privateKey
=
$private_key
;
}
/**
* Sets the $request property.
*
* @param \Symfony\Component\HttpFoundation\Request $request
* The HttpRequest object representing the current request.
*/
public
function
setRequest
(
Request
$request
)
{
$this
->
request
=
$request
;
}
/**
* Generates a token based on $value, the user session, and the private key.
*
* @param string $value
* (optional) An additional value to base the token on.
*
* @return string
* A 43-character URL-safe token for validation, based on the user session
* ID, the hash salt provided by drupal_get_hash_salt(), and the
* 'drupal_private_key' configuration variable.
*
* @see drupal_get_hash_salt()
*/
public
function
get
(
$value
=
''
)
{
return
Crypt
::
hmacBase64
(
$value
,
session_id
()
.
$this
->
privateKey
->
get
()
.
drupal_get_hash_salt
());
}
/**
* Validates a token based on $value, the user session, and the private key.
*
* @param string $token
* The token to be validated.
* @param string $value
* (optional) An additional value to base the token on.
* @param bool $skip_anonymous
* (optional) Set to TRUE to skip token validation for anonymous users.
*
* @return bool
* TRUE for a valid token, FALSE for an invalid token. When $skip_anonymous
* is TRUE, the return value will always be TRUE for anonymous users.
*/
public
function
validate
(
$token
,
$value
=
''
,
$skip_anonymous
=
FALSE
)
{
$user
=
$this
->
request
->
attributes
->
get
(
'account'
);
return
(
$skip_anonymous
&&
$user
->
id
()
==
0
)
||
(
$token
==
$this
->
get
(
$value
));
}
}
core/lib/Drupal/Core/PrivateKey.php
0 → 100644
View file @
882ef344
<?php
/**
* @file
* Contains \Drupal\Core\PrivateKey.
*/
namespace
Drupal\Core
;
use
Drupal\Core\KeyValueStore\KeyValueStoreInterface
;
use
Drupal\Component\Utility\Crypt
;
/**
* Manages the Drupal private key.
*/
class
PrivateKey
{
/**
* The state service.
*
* @var \Drupal\Core\KeyValueStore\KeyValueStoreInterface
*/
protected
$state
;
/**
* Constructs the token generator.
*
* @param \Drupal\Core\KeyValueStore\KeyValueStoreInterface $state
* The state service.
*/
function
__construct
(
KeyValueStoreInterface
$state
)
{
$this
->
state
=
$state
;
}
/**
* Gets the private key.
*
* @return string
* The private key.
*/
public
function
get
()
{
if
(
!
$key
=
$this
->
state
->
get
(
'system.private_key'
))
{
$key
=
$this
->
create
();
$this
->
set
(
$key
);
}
return
$key
;
}
/**
* Sets the private key.
*
* @param string $key
* The private key to set.
*/
public
function
set
(
$key
)
{
return
$this
->
state
->
set
(
'system.private_key'
,
$key
);
}
/**
* Creates a new private key.
*
* @return string
* The private key.
*/
protected
function
create
()
{
return
Crypt
::
randomStringHashed
(
55
);
}
}
core/tests/Drupal/Tests/Core/Access/CsrfTokenGeneratorTest.php
0 → 100644
View file @
882ef344
<?php
/**
* @file
* Contains \Drupal\Tests\Core\Access\CsrfTokenGeneratorTest.
*/
namespace
Drupal\Tests\Core\Access
{
use
Drupal\Tests\UnitTestCase
;
use
Drupal\Core\Access\CsrfTokenGenerator
;
use
Drupal\Component\Utility\Crypt
;
use
Symfony\Component\HttpFoundation\Request
;
/**
* Tests the CSRF token generator.
*/
class
CsrfTokenGeneratorTest
extends
UnitTestCase
{
/**
* The CSRF token generator.
*
* @var \Drupal\Core\Access\CsrfTokenGenerator
*/
protected
$generator
;
public
static
function
getInfo
()
{
return
array
(
'name'
=>
'CsrfTokenGenerator test'
,
'description'
=>
'Tests the CsrfTokenGenerator class.'
,
'group'
=>
'Access'
);
}
/**
* {@inheritdoc}
*/
function
setUp
()
{
parent
::
setUp
();
$this
->
key
=
Crypt
::
randomStringHashed
(
55
);
$private_key
=
$this
->
getMockBuilder
(
'Drupal\Core\PrivateKey'
)
->
disableOriginalConstructor
()
->
setMethods
(
array
(
'get'
))
->
getMock
();
$private_key
->
expects
(
$this
->
any
())
->
method
(
'get'
)
->
will
(
$this
->
returnValue
(
$this
->
key
));
$this
->
generator
=
new
CsrfTokenGenerator
(
$private_key
);
$this
->
generator
->
setRequest
(
new
Request
());
}
/**
* Tests CsrfTokenGenerator::get().
*/
public
function
testGet
()
{
$this
->
assertInternalType
(
'string'
,
$this
->
generator
->
get
());
$this
->
assertNotSame
(
$this
->
generator
->
get
(),
$this
->
generator
->
get
(
$this
->
randomName
()));
$this
->
assertNotSame
(
$this
->
generator
->
get
(
$this
->
randomName
()),
$this
->
generator
->
get
(
$this
->
randomName
()));
}
/**
* Tests CsrfTokenGenerator::validate().
*/
public
function
testValidate
()
{
$token
=
$this
->
generator
->
get
();
$this
->
assertTrue
(
$this
->
generator
->
validate
(
$token
));
$this
->
assertFalse
(
$this
->
generator
->
validate
(
$token
,
'foo'
));
$token
=
$this
->
generator
->
get
(
'bar'
);
$this
->
assertTrue
(
$this
->
generator
->
validate
(
$token
,
'bar'
));
}
}
}
/**
* @todo Remove this when https://drupal.org/node/2036259 is resolved.
*/
namespace
{
if
(
!
function_exists
(
'drupal_get_hash_salt'
))
{
function
drupal_get_hash_salt
()
{
return
hash
(
'sha256'
,
'test_hash_salt'
);
}
}
}
core/tests/Drupal/Tests/Core/PrivateKeyTest.php
0 → 100644
View file @
882ef344
<?php
/**
* @file
* Contains \Drupal\Tests\Core\PrivateKeyTest.
*/
namespace
Drupal\Tests\Core
;
use
Drupal\Core\PrivateKey
;
use
Drupal\Tests\UnitTestCase
;
use
Drupal\Component\Utility\Crypt
;
/**
* Tests the private key service.
*/
class
PrivateKeyTest
extends
UnitTestCase
{
/**
* The state mock class.
*
* @var \Drupal\Core\KeyValueStore\KeyValueStoreInterface|\PHPUnit_Framework_MockObject_MockObject
*/
protected
$state
;
/**
* The private key service mock.
*
* @var \Drupal\Core\PrivateKey
*/
protected
$privateKey
;
/**
* The random key to use in tests.
*
* @var string
*/
protected
$key
;
public
static
function
getInfo
()
{
return
array
(
'name'
=>
'PrivateKey test'
,
'description'
=>
'Tests the PrivateKey class.'
,
'group'
=>
'System'
);
}
/**
* {@inheritdoc}
*/
public
function
setUp
()
{
parent
::
setUp
();
$this
->
key
=
Crypt
::
randomStringHashed
(
55
);
$this
->
state
=
$this
->
getMock
(
'Drupal\Core\KeyValueStore\KeyValueStoreInterface'
);
$this
->
privateKey
=
new
PrivateKey
(
$this
->
state
);
}
/**
* Tests PrivateKey::get().
*/
public
function
testGet
()
{
$this
->
state
->
expects
(
$this
->
once
())
->
method
(
'get'
)
->
with
(
'system.private_key'
)
->
will
(
$this
->
returnValue
(
$this
->
key
));
$this
->
assertEquals
(
$this
->
key
,
$this
->
privateKey
->
get
());
}
/**
* Tests PrivateKey::get() with no private key from state.
*/
public
function
testGetNoState
()
{
$this
->
assertInternalType
(
'string'
,
$this
->
privateKey
->
get
());
}
/**
* Tests PrivateKey::setPrivateKey().
*/
public
function
testSet
()
{
$random_name
=
$this
->
randomName
();
$this
->
state
->
expects
(
$this
->
once
())
->
method
(
'set'
)
->
with
(
'system.private_key'
,
$random_name
)
->
will
(
$this
->
returnValue
(
TRUE
));
$this
->
privateKey
->
set
(
$random_name
);
}
}
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
.
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment