djoos / escapewsseauthenticationbundle Goto Github PK
View Code? Open in Web Editor NEWSymfony bundle to implement WSSE authentication
Home Page: http://symfony.com/doc/current/cookbook/security/custom_authentication_provider.html
Symfony bundle to implement WSSE authentication
Home Page: http://symfony.com/doc/current/cookbook/security/custom_authentication_provider.html
hello,
I didnt know if my question is correct.
I install a bundle and login with WSSEauthentification.
/**
* @Route("/call", name="test_call")
* @Template()
*/
public function callAction()
{
$curl_handle = curl_init();
curl_setopt($curl_handle, CURLOPT_URL, 'http://localhost/wazazazaa/web/app_dev.php/getToken');
curl_setopt($curl_handle, CURLOPT_HTTPHEADER, array($this->generate_wsse_header('user', 'userpass')));
curl_exec($curl_handle);
echo curl_getinfo($curl_handle, CURLINFO_HTTP_CODE);
curl_close($curl_handle);
die;
}
private function generate_wsse_header($username, $secret)
{
// date_default_timezone_set('Europe/Paris');
$nonce = md5(rand(), true);
$created = date(DATE_ATOM);
$digest = base64_encode(sha1($nonce.$created.$secret,true));
$b64nonce = base64_encode($nonce);
return sprintf('X-WSSE: UsernameToken Username="%s", PasswordDigest="%s", Nonce="%s", Created="%s"',
$username,
$digest,
$b64nonce,
$created
);
}
the log in is ok but how can get a token?
i would like to call a webservice /api/* if only i logged in with WSSE authentification.
I have seen that the wsse authentification had a lifetime , how could i use this time when i am logged to call another webservice ??
maybe i must to use nonces?
thank to -)
Hi!
I am creating an application in AngularJS that will be served by a REST in Symfony with WSSE authentication, could configure and test everything right, is working perfectly!
I have difficulty understanding what will be the authentication cycle "AngularJS> REST API"
From what I understand, when the user logs in, I have to call a method that returns me the password hash ok? This method will have to be without authentication.
With this hash I'll be able to create the WSSE header and authenticate me in REST.
I need you to help me better understand this cycle!
Congratulations on this bundle is perfect!
Wondering if you'd consider adding me to help maintain this bundle. We're using it but there's a few improvement sand code style changes that can be made. If not I'll just work thru pull requests
Hi guys.
Is there an example of use of this bundle?
I have already installed it but I'm a little lost yet and I don't even know how to use it
Can anybody help me?
Thanks a lot.
I'm using Symfony 2.0.22.
when I update the config.yml as it is in the documentation
I have this error
InvalidConfigurationException: Unrecognized options "provider_class, listener_class" under "escape_wsse_authentication"
How can I solve this ?
Thank U :)
Hello !
We had this webserver were the date was slightly in the past (4 minutes): the API kept returning 401 Unauthorized errors and there was absolutely no trace of the calls in the production log.
In debug mode I found this: "Future token detected" which actually made sens but was logged with a "debug" level.
I tried to figure out why no error was logged and I found this:
Escape\WSSEAuthenticationBundle\Security\Http\EntryPoint\EntryPoint:32
if($ae instanceof AuthenticationException)
{
$this->logger->debug($ae->getMessage());
}
It seems to me that the criticality of the AuthenticationExceptions was a little bit underestimated (documentation) and should be at least a Warning.
Thanks for your awesome bundles by the way :)
Hello,
I have a problem in getting a wsse authentication running using your bundle (thx!) and fosuserbundle. I'm able to login (i can see in the log that the user is granted access.. also visible in the profiler security tab, user last_login gets updated in db etc etc).
I also created a Handler that listens for onAuthenticationSuccess
and returns the contents of X-WSSE
header (i can't remember where i saw a similar script):
// Acme\AuthBundle\Security\Authentication\Handler;
public function onAuthenticationSuccess(Request $request, TokenInterface $token) {
$user = $this->security->getToken()->getUser();
$created = date('c');
$nonce = substr(md5(uniqid('nonce_', true)), 0, 16);
$nonceHigh = base64_encode($nonce);
$passwordDigest = base64_encode(sha1($nonceHigh . $created . $user->getPassword() . "{".$user->getSalt()."}", true));
$header = "UsernameToken Username=\"{$user->getUsername()}\", PasswordDigest=\"{$passwordDigest}\", Nonce=\"{$nonceHigh}\", Created=\"{$created}\"";
return new Response($header);
}
After that, I take the header, paste it in the Chrome Rest Console... but I get a 401. Here is the log of such request:
[2014-04-15 14:57:36] event.DEBUG: Notified event "kernel.request" to listener "Symfony\Component\HttpKernel\EventListener\ProfilerListener::onKernelRequest". [] []
[2014-04-15 14:57:36] event.DEBUG: Notified event "kernel.request" to listener "Symfony\Bundle\FrameworkBundle\EventListener\SessionListener::onKernelRequest". [] []
[2014-04-15 14:57:36] event.DEBUG: Notified event "kernel.request" to listener "Symfony\Component\HttpKernel\EventListener\FragmentListener::onKernelRequest". [] []
[2014-04-15 14:57:36] event.DEBUG: Notified event "kernel.request" to listener "Symfony\Component\HttpKernel\EventListener\RouterListener::onKernelRequest". [] []
[2014-04-15 14:57:36] request.INFO: Matched route "mma_backend_company_get" (parameters: "_controller": "MMAHotel\BackendBundle\Controller\CompanyController::getAction", "_format": "json", "uid": "1234x", "_route": "mma_backend_company_get") [] []
[2014-04-15 14:57:36] event.DEBUG: Notified event "kernel.request" to listener "Symfony\Component\HttpKernel\EventListener\LocaleListener::onKernelRequest". [] []
[2014-04-15 14:57:36] event.DEBUG: Notified event "kernel.request" to listener "FOS\RestBundle\EventListener\BodyListener::onKernelRequest". [] []
[2014-04-15 14:57:36] event.DEBUG: Notified event "kernel.request" to listener "Symfony\Component\Security\Http\Firewall::onKernelRequest". [] []
[2014-04-15 14:57:36] doctrine.DEBUG: SELECT t0.username AS username1, t0.username_canonical AS username_canonical2, t0.email AS email3, t0.email_canonical AS email_canonical4, t0.enabled AS enabled5, t0.salt AS salt6, t0.password AS password7, t0.last_login AS last_login8, t0.locked AS locked9, t0.expired AS expired10, t0.expires_at AS expires_at11, t0.confirmation_token AS confirmation_token12, t0.password_requested_at AS password_requested_at13, t0.roles AS roles14, t0.credentials_expired AS credentials_expired15, t0.credentials_expire_at AS credentials_expire_at16, t0.id AS id17, t0.uid AS uid18, t0.firstname AS firstname19, t0.lastname AS lastname20, t0.fullname AS fullname21, t0.phone AS phone22, t0.skype AS skype23, t0.handle AS handle24, t0.company_id AS company_id25 FROM User t0 WHERE t0.username_canonical = ? LIMIT 1 ["mihai"] []
[2014-04-15 14:57:36] app.DEBUG: Previously used nonce detected. [] []
[2014-04-15 14:57:36] event.DEBUG: Listener "Symfony\Component\Security\Http\Firewall::onKernelRequest" stopped propagation of the event "kernel.request". [] []
[2014-04-15 14:57:36] event.DEBUG: Listener "Symfony\Bundle\AsseticBundle\EventListener\RequestListener::onKernelRequest" was not called for event "kernel.request". [] []
[2014-04-15 14:57:36] event.DEBUG: Listener "Symfony\Component\HttpKernel\EventListener\ErrorsLoggerListener::injectLogger" was not called for event "kernel.request". [] []
[2014-04-15 14:57:36] event.DEBUG: Listener "Symfony\Component\HttpKernel\EventListener\ErrorsLoggerListener::injectLogger" was not called for event "kernel.request". [] []
[2014-04-15 14:57:36] event.DEBUG: Notified event "kernel.response" to listener "Symfony\Component\HttpKernel\EventListener\ResponseListener::onKernelResponse". [] []
[2014-04-15 14:57:36] event.DEBUG: Notified event "kernel.response" to listener "Symfony\Component\Security\Http\RememberMe\ResponseListener::onKernelResponse". [] []
[2014-04-15 14:57:36] event.DEBUG: Notified event "kernel.response" to listener "Sensio\Bundle\FrameworkExtraBundle\EventListener\HttpCacheListener::onKernelResponse". [] []
[2014-04-15 14:57:36] event.DEBUG: Notified event "kernel.response" to listener "Symfony\Component\HttpKernel\EventListener\ProfilerListener::onKernelResponse". [] []
[2014-04-15 14:57:36] event.DEBUG: Notified event "kernel.response" to listener "Symfony\Bundle\WebProfilerBundle\EventListener\WebDebugToolbarListener::onKernelResponse". [] []
[2014-04-15 14:57:36] event.DEBUG: Notified event "kernel.response" to listener "Symfony\Component\HttpKernel\EventListener\StreamedResponseListener::onKernelResponse". [] []
[2014-04-15 14:57:36] event.DEBUG: Notified event "kernel.finish_request" to listener "Symfony\Component\HttpKernel\EventListener\LocaleListener::onKernelFinishRequest". [] []
[2014-04-15 14:57:36] event.DEBUG: Notified event "kernel.finish_request" to listener "Symfony\Component\HttpKernel\EventListener\RouterListener::onKernelFinishRequest". [] []
[2014-04-15 14:57:36] event.DEBUG: Notified event "kernel.finish_request" to listener "Symfony\Component\Security\Http\Firewall::onKernelFinishRequest". [] []
[2014-04-15 14:57:36] event.DEBUG: Notified event "kernel.terminate" to listener "Symfony\Bundle\SwiftmailerBundle\EventListener\EmailSenderListener::onTerminate". [] []
[2014-04-15 14:57:36] event.DEBUG: Notified event "kernel.terminate" to listener "Symfony\Component\HttpKernel\EventListener\ProfilerListener::onKernelTerminate". [] []
I also tried generating the header using teria.com generator (got the salt+pass for db), but the problem persists.
Here is my security.yml
security:
encoders:
FOS\UserBundle\Model\UserInterface: sha512
role_hierarchy:
ROLE_ADMIN: ROLE_USER
ROLE_SUPER_ADMIN: [ROLE_USER, ROLE_ADMIN, ROLE_ALLOWED_TO_SWITCH]
providers:
fos_userbundle:
id: fos_user.user_provider.username
firewalls:
wsse_secured:
pattern: ^/back/.*
wsse:
lifetime: 300
realm: "Acme API"
profile: "UsernameToken"
encoder: #digest algorithm
algorithm: sha512
encodeHashAsBase64: true
iterations: 1
anonymous : true
stateless: true
wsse_auth:
pattern: ^/wsse
form_login:
provider: fos_userbundle
login_path: acme_auth_wsse_login
check_path: acme_auth_wsse_login_check
success_handler: acme.handler.wsse_login_success
require_previous_session: false
anonymous: true
Does anyone have any idea what I'm missing?
Thank you
I don't know why I am unable to reuse the nonce and I have set the lifetime for nonce to be 5184000 already.
Here is my config.yml:
firewalls:
wsse_secured:
pattern: ^/api
provider: fos_userbundle
stateless: true
wsse:
nonce_dir: "/nonce" #location where nonces will be saved; use null to skip nonce-validation
lifetime: 5184000 #lifetime of nonce
realm: "Secured API" #identifies the set of resources to which the authentication information will apply (WWW-Authenticate)
profile: "UsernameToken" #WSSE profile (WWW-Authenticate)
encoder: #digest algorithm
algorithm: sha1
encodeHashAsBase64: true
iterations: 1
I have another question that I am building a single paged website that will keep requesting my REST API developed with FOSRestBundle. However different resources require different privileges that user needs to be logged first.
For testing, if my REST API is secured by HTTP authentication, I cannot test it with REST client. If I use WSSE, I can test the service but it is complicated to use over webpage.
Should I use WSSE for authenticating users or HTTP authenticating would be better? WSSE seems not quite suuitable for webpage. Or if I can authenticate user and give them a token in WSSE if user is logged in?
Thanks for helping.
Hello,
I'm tring to get authenticated using api tokens with EscapeWSSEAuthenticationBundle.
I can receive generated tokens at login but when I tried to send tokens back with another request, listener is not receiving headers I sent like X-WSSE and Authentication.
here is the my jquery code I'm tring
jQuery.ajax (
{
type: 'GET',
dataType: "jsonp",
url: this.apiUrl + req,
//headers: JSON.stringify(this.token),
beforeSend: function (xhrObj) {
alert(that.token[1]);
//xhr.withCredentials = true;
xhrObj.setRequestHeader(
"HTTP-Authentication",'WSSE profile="UsernameToken"'
);
xhrObj.setRequestHeader("X-WSSE", "'"+that.token[1]+"'");
//xhr.setRequestHeader('Access-Control-Allow-Origin', '*');
},
success: function(response)
{
console.log(response);
$('#responseBody').html(response);
}
});
could you pls. help me to fix this issue asap?
You are using a Doctrine Common cache but it's not required in the composer.json file.
Hi,
An error seems to exist with "wsse" security.yml firewall parameter.
Here is returned error:
InvalidConfigurationException: Unrecognized options "wsse" under "security.firewalls.wsse_secured".
An idea to fix it?
Thank you.
If the nonce contains a slash, what is possible even with base64 encoding, the file_put_contents function will fail.
Hi,
I have completed programming an API and I'm looking into securing it using WSSE.
I'm having some trouble getting authenticated to the secured parts of the api.
My configuration is as follows:
security.yml
security:
providers:
fos_userbundle:
id: fos_user.user_provider.username_email
encoders:
FOS\UserBundle\Model\UserInterface: sha512
role_hierarchy:
ROLE_ADMIN: ROLE_USER
ROLE_SUPER_ADMIN: ROLE_ADMIN
firewalls:
wsse_secured:
pattern: ^/api/.*
wsse:
lifetime: 300 #lifetime of nonce
realm: "Secured API" #identifies the set of resources to which the authentication information will apply (WWW-Authenticate)
profile: "UsernameToken" #WSSE profile (WWW-Authenticate)
encoder: #digest algorithm
algorithm: sha512
anonymous: true
provider: fos_userbundle
access_control:
- { path: ^/api.*, role: ROLE_USER }
- { path: ^/security.*, role: IS_AUTHENTICATED_ANONYMOUSLY }
config.yml
...
fos_user:
db_driver: orm
firewall_name: wsse_secured
user_class: MyCompany\UserBundle\Entity\User
escape_wsse_authentication:
authentication_provider_class: Escape\WSSEAuthenticationBundle\Security\Core\Authentication\Provider\Provider
authentication_listener_class: Escape\WSSEAuthenticationBundle\Security\Http\Firewall\Listener
authentication_entry_point_class: Escape\WSSEAuthenticationBundle\Security\Http\EntryPoint\EntryPoint
authentication_encoder_class: Symfony\Component\Security\Core\Encoder\MessageDigestPasswordEncoder
...
SecurityController.php
/**
* WSSE Token generation
*
* @Rest\View
*
* @return FOSView
* @throws AccessDeniedException
*/
public function postTokenCreateAction()
{
$view = FOSView::create();
$request = $this->getRequest();
$username = $request->get('_username');
$password = $request->get('_password');
//$csrfToken = $this->container->get('form.csrf_provider')->generateCsrfToken('authenticate');
//$data = array('csrf_token' => $csrfToken,);
$um = $this->get('fos_user.user_manager');
$user = $um->findUserByUsernameOrEmail($username);
if (!$user instanceof User) {
throw new AccessDeniedException("Wrong user");
}
$created = date('c');
$nonce = substr(md5(uniqid('nonce_', true)), 0, 16);
$nonceHigh = base64_encode($nonce);
$passwordDigest = base64_encode(sha1($nonce . $created . $password . "{".$user->getSalt()."}", true));
$header = "UsernameToken Username=\"{$username}\", PasswordDigest=\"{$passwordDigest}\", Nonce=\"{$nonceHigh}\", Created=\"{$created}\"";
$view->setHeader("Authorization", 'WSSE profile="UsernameToken"');
$view->setHeader("X-WSSE", "UsernameToken Username=\"{$username}\", PasswordDigest=\"{$passwordDigest}\", Nonce=\"{$nonceHigh}\", Created=\"{$created}\"");
$data = array('WSSE' => $header);
$view->setStatusCode(200)->setData($data);
return $view;
}
The tokens are getting generated by doing
POST /security/create_token.json?username=myusername&password="plaintextpassword" over SSL
But when I use that token with a X-WSSE header to go to
GET /api/me
I keep getting a 401 Not Authorized.
Any ideas? Did I misinterpreted the documentation?
Hi,
I try to integrate FOSUserBundle with EscapeWSSEAuthenticationBundle.
I read and worked through the other issues related to this. But I still have an error "WSSE authentication failed" in my logs and it don't work.
Here is my security.yml:
security:
encoders:
FOS\UserBundle\Model\UserInterface: sha512
role_hierarchy:
ROLE_ADMIN: ROLE_USER
ROLE_SUPER_ADMIN: ROLE_ADMIN
providers:
fos_userbundle:
id: fos_user.user_provider.username_email
firewalls:
dev:
pattern: ^/(_(profiler|wdt)|css|images|js)/
security: false
wsse_secured:
pattern: ^/api/.*
wsse:
realm: "Gesicherte API. Bitte anmelden!"
profile: "UsernameToken"
lifetime: 300
encoder:
algorithm: sha512
anonymous: false
provider: fos_userbundle
main:
pattern: ^/
form_login:
provider: fos_userbundle
csrf_provider: form.csrf_provider
logout: true
anonymous: true
access_control:
- { path: ^/login$, role: IS_AUTHENTICATED_ANONYMOUSLY }
- { path: ^/register, role: IS_AUTHENTICATED_ANONYMOUSLY }
- { path: ^/resetting, role: IS_AUTHENTICATED_ANONYMOUSLY }
- { path: ^/admin/, role: ROLE_ADMIN }
That's the relevant part of config.yml
fos_rest:
view:
view_response_listener: true
fos_user:
db_driver: orm
firewall_name: wsse_secured
user_class: dpn\DienstplanBundle\Entity\User
escape_wsse_authentication:
authentication_provider_class: Escape\WSSEAuthenticationBundle\Security\Core\Authentication\Provider\Provider
authentication_listener_class: Escape\WSSEAuthenticationBundle\Security\Http\Firewall\Listener
authentication_entry_point_class: Escape\WSSEAuthenticationBundle\Security\Http\EntryPoint\EntryPoint
authentication_encoder_class: Symfony\Component\Security\Core\Encoder\MessageDigestPasswordEncoder
In vendor/escapestudios/wsse-authentication-bundle/Escape/WSSEAuthenticationBundle/Security/Core/Authentication/Provider/Provider.php I debugged into validateDiget Method. The value in $expected is not the same as in $digest.
For testing I used http://www.teria.com/~koseki/tools/wssegen/ for generating WSSE Header. I put in my username and the hashed password, taken from the database. Nonce and Created are set to auto. I took the generated WSSE Header and tried to test my api with the Chrome Rest Console.
There I get an error 401.
Are there any known errors or have I missed something?
I use symfony version 2.4.4, FOSUser version 2.0.0 and EscapeWSSEAuthenticationBundle 2.3.1
The deprecation warning in the Symfony security component is causing unit tests to fail.
I don't know the proper way to handle this. You cannot "fix" the problem by not using the SecurityContextInterface, because you then break compatibility with older Symfony versions.
You also cannot tell phpunit to NOT convert these to errors. If you look here, you can see that we'd have to turn off convertErrorsToExceptions
completely to fix this problem. You can't just have phpunit ignore deprecation errors w/o also ignoring all the other errors.
Do you have any idea on how best to resolve this?
I'm trying to use a unified response body for any 4xx or 5xx errors in an API that uses this bundle for authentication. Something like this:
{
"error": {
"http_status_code": 401,
"message": "Unauthorized"
}
}
When there is an authentication error (like a malformed WSSE header or incorrect header), then this bundle just returns a basic response with the code set to 401 and some WSSE authenticate headers.
I've been looking thru the Security component trying to figure out how all this works - It looks normally when there's an AuthenticationException, the user is typically redirected to some failure page (or the login page) and a message is saved to the session explaining the error.
So I'm not sure in any normal circumstance Symfony actually returns a 401 page and template.
Has anyone been able to get a template for 401s?
Hi,
I'm having the same problem as @djoos was having and i followed every step of your discussion on #49 without success.
The only difference from your tutorial is that i'm using sha512 as FOS encoder. So i changed the encoder parameter to sha512 and made a custom function to generate my token (based on https://github.com/sdiaz/FOSRestBundleByExample/blob/master/src/ByExample/DemoBundle/Controller/SecurityController.php#L64 ).
Still without success, please could you explain what i've been doing wrong ?
Thank's
PS : here is my code
security:
providers:
main:
id: fos_user.user_provider.username
wsse_secured:
pattern: ^/api/.*
anonymous: false
provider: main
wsse:
lifetime: 31556926
realm: "Secured API"
profile: "UsernameToken"
encoder:
algorithm: sha512
encodeHashAsBase64: true
iterations: 1
encoders:
Alpixel\Component\UserBundle\Entity\User: sha512
I also made the modification about the Authentication provider
Hello !
EscapeWSSEAuthenticationBundle worked great for several months now, but after I updated to the latest version I get this error message if I try to clear the symfony cache:
[Symfony\Component\Debug\Exception\ContextErrorException]
Catchable Fatal Error: Argument 2 passed to MyAuthenticationProvider::__construct() must implement interface Symfony\Component\Security\Core\Encoder\PasswordEncoderInterface, string given, called in /cache-path/ap_DevDebugProjectContainer.php on line 1879 and defined
Do you have an idea how to fix this ?
Thanks in advance !
Hi,
after installing the bundle I get the following error:
InvalidConfigurationException: Unrecognized options "realm, profile, lifetime" under "security.firewalls.wsse_secured.wsse"
That's my app/config/security.yml: https://gist.github.com/dce424008755c0f6c56d.git
And here's my app/AppKernel.php: https://gist.github.com/ad644b9cc9cdca395900.git
Best regards.
Using semver.org
Hi djoos!
I have a problem with following configuration
api:
pattern: ^/api/v.*
stateless: true
provider: api_user
wsse:
realm: "%api_wsse_realm%" #identifies the set of resources to which the authentication information will apply (WWW-Authenticate)
profile: "%api_wsse_profile%" #WSSE profile (WWW-Authenticate)
lifetime: "%api_wsse_lifetime%"
encoder:
algorithm: "%api_wsse_algorithm%"
encodeHashAsBase64: "%api_wsse_encodehashasbase64%"
iterations: "%api_wsse_iterations%"
http_basic: ~
Http_basic make it crash with "This token has no "nonce" attribute." because it trying to get value token value in Escape\WSSEAuthenticationBundle\Security\Core\Authentication\Provider\Provider line 66
I dont know why is inside it but if I override authentication_provider_class two AuthenticationProviders work
public function authenticate(TokenInterface $token)
{
if (!$token->hasAttribute('nonce'))
return;
return parent::authenticate($token);
}
What is wrong here?
Thanks in advance djoos!
Hello,
what is happening is the following.
I'm testing the REST api in sandbox NelmioDoc.
The first time I open the browser, I try the request without sending the wsse header and returns 401, expected result.
When I add the header WSSE, returns 200, expected result.
When I make a new request with the same header, returns 401, expected result.
Now the possible problem, when I remove the header and make the request again, returns 200, not expected.
Why does it happen?
Should not deny request, and the header wsse not exist?
hi i recently tried integrating this to s2.1 (master) and it didnt really work, i think some things might have changed under the hood, but not sure yet, just wanted to know if you already have plans in porting this to symfony master or if its ok if i try getting it work and create a new branch? cheers phil
How about adding a command for purging expired nonces? It would be useful to put it in a cronjob to mantain the nonce folder clean.
Hi @djoos !
I discover your bundle recently and I'm very interesting about it, but I can't login me with my configuration of security.yml. I looked a lot of issue that you fixed but it didn't work for me.
Please, can you explain me the way to integrate it successfully ?
My security.yml :
encoders:
FOS\UserBundle\Model\UserInterface: sha512
providers:
fos_userbundle:
id: fos_user.user_provider.username
firewalls:
wsse_secured:
pattern: ^/api/.*
wsse:
lifetime: 300 #lifetime of nonce
realm: "Secured API" #identifies the set of resources to which the authentication information will apply (WWW-Authenticate)
profile: "UsernameToken" #WSSE profile (WWW-Authenticate)
encoder: #digest algorithm
algorithm: sha1
encodeHashAsBase64: true
iterations: 1
anonymous: true
provider: fos_userbundle
access_control:
- { path: ^/api.*, role: ROLE_USER }
- { path: ^/, role: ROLE_USER }
My config.yml :
fos_user:
db_driver: orm
firewall_name: wsse_secured
user_class: Bg\UserBundle\Entity\User
escape_wsse_authentication:
authentication_provider_class: Escape\WSSEAuthenticationBundle\Security\Core\Authentication\Provider\Provider
authentication_listener_class: Escape\WSSEAuthenticationBundle\Security\Http\Firewall\Listener
authentication_entry_point_class: Escape\WSSEAuthenticationBundle\Security\Http\EntryPoint\EntryPoint
authentication_encoder_class: Symfony\Component\Security\Core\Encoder\MessageDigestPasswordEncoder
I installed this bundle but I get WSSE authentication failed on dev.log file. This is my configuration:
security:
providers:
fos_userbundle:
id: fos_user.user_provider.username_email
encoders:
FOS\UserBundle\Model\UserInterface: sha512
firewalls: #important! user same tab size :)
dev:
pattern: ^/(_(profiler|wdt)|css|images|js)/
security: false
wsse_secured:
pattern: ^/api/.*
wsse:
realm: "Secured with WSSE" #identifies the set of resources to which the authentication information will apply (WWW-Authenticate)
profile: "UsernameToken" #WSSE profile (WWW-Authenticate)
provider: fos_userbundle
encoder: #digest algorithm
algorithm: sha1
encodeHashAsBase64: true
iterations: 512
I'm using this tool to generate the WSSE Header: http://www.teria.com/~koseki/tools/wssegen/ and for the password I'm using the encrypted salt concatenated with the password as it is in the database. What's the problem? I'm using Chrome's Extension REST Console.
Thank you
DeleteNoncesCommand
calls flushAll()
to flush the entries. If you are using Redis this will issue a FlushDB command that will drop your whole Redis DB.
Am I confused or the nonce expiry calculation in the authentication provider is incorrect?
Current:
if (nonce_timestamp + lifetime > current_timestamp)
then throw NonceExpiredException
Note that the bigger the lifetime, the more chances to get the exception, which doesn't make sense.
Expected:
if (current_timestamp - nonce_timestamp > lifetime)
then throw NonceExpiredException
Hi,
I want to create some tests for my REST Api, that i auth with wsse.
But I dont know how to write the part about wsse.
Could anyone please write down an example of a test for a call that must be authenticated with wsse?
I know this is not really a issue, but i thought this is the best place where to ask.
Thanks in advance,
C
Hi,
I am a little bit stucked with my project where I want to achieve opening API URLs (FOSRestBundle) as authenticated user (ROLE_ADMIN) and using WSSE header for non-authenticated user. So basically, any API URL should be accessible when:
Unfortunate I am not allowed to share project specific details; but here some configuration parts
security:
firewalls:
api_secured:
pattern: ^/api
wsse:
realm: "Secured with WSSE"
profile: "UsernameToken"
encoder:
algorithm: sha1
secured_area:
pattern: ^/
anonymous: ~
form_login:
...
The /api URLs are also inside "access_control"
access_control:
...
- { path: ^/api, roles: [ROLE_ADMIN, ROLE_API] }
...
The ROLE_API is assigned to a "memory user", which is used for external access.
It's no problem to move this user to FOSUserBundle if that would fix this :-)
Besides that, I have setupped a "chain_provider" like this;
providers:
chain_provider:
chain:
providers: [main, wsse_users]
...
WSSE configuration (default);
# Escape WSSE authentication configuration
escape_wsse_authentication:
authentication_provider_class: Escape\WSSEAuthenticationBundle\Security\Core\Authentication\Provider\Provider
authentication_listener_class: Escape\WSSEAuthenticationBundle\Security\Http\Firewall\Listener
authentication_entry_point_class: Escape\WSSEAuthenticationBundle\Security\Http\EntryPoint\EntryPoint
authentication_encoder_class: Symfony\Component\Security\Core\Encoder\MessageDigestPasswordEncoder
I also use "PdoSessionHandler" to store sessions in the database.
Many many thanks for any help getting this to work.
Authentication shouldnt be enforced for routes if IS_AUTHENTICATED_ANONYMOUSLY
wsse_secured:
provider: fos_userbundle.wsse
pattern: ^/api/.*
access_control:
- { path: ^/api/v1/public/new.$, role: IS_AUTHENTICATED_ANONYMOUSLY }
- { path: ^/api/., role: ROLE_MOBILE }
401 Unauthorized
Within my application I have two kinds of users (usersA, usersB) that are registered with custom providers (one for each kind of user: providerA and providerB). I have also two different routes (/apiA/ , /apiB/). apiA should check for usersA and apiB for usersB.
I have thus two firewall definitions, and I want to use the WSSE authentication method for both.
The problem is that both firewalls seem to use the same provider (it looks like it's the provider of the first defined firewall that uses wsse) so it fails to recognize the correct user type for one of the two routes.
Here's my security.yml file:
yaml
providers:
providerA:
id: my_providers.providerA
providerB:
id: my_providers.providerB
firewalls:
fireA:
pattern: ^/apiA/
provider: providerA
wsse:
realm: "Secured with WSSE"
profile: "UsernameToken"
fireB:
pattern: ^/apiB/
provider: providerB
wsse:
realm: "Secured with WSSE"
profile: "UsernameToken"
access_control:
- { path: ^/apiA/, role: ROLE_USER_A }
- { path: ^/apiB/, role: ROLE_USER_B }
When I reach /apiB/, providerA is used instead of providerB, and it fails to authenticate my users correctly because they are mistaken for another type.
Does this bundle support multiple providers? Shouldn't we have an extra parameter under wsse: that defines the provider to use behind this authentication (like how it's done for [http_basic, x509...](http://symfony.com/doc/current/reference/configuration/security.html) ) ?
Thanks a lot!
Write up more supporting material for easier implementation of the bundle.
Elaborate WSSE Authentication bundle + FOSUser bundle as well, as this seems to be a FAQ...
UsernameToken strings with non ascii letters fail to authenticate.
Add
$user = $this->userProvider->loadUserByUsername(urldecode($token->getUsername()));
in Escape\WSSEAuthenticationBundle\Security\Core\Authentication\Provider\Provider at line 43
Hello,
I'm trying to setup EscapeWSSEAuthenticationBundle and FOSUserBundle to secure my api. Does someone know a good tutorial about this ?
I tried it with this info :
#31
but it is to much fragmented. I didn't get it to work ...
Thanks in advance.
Latest commit is requesting a Nonce attribute in lowercase, and doing so results in expected failure to authenticate. Not doing so results in the error above.
Rolling back to commit #e1569417f094d9f89e3c40a4b39fcb0f41b62d4d resolves the issue.
I tried to write a bugfix for #69, however, the unit tests for the stock repository version fail:
PHP Warning: Erroneous data format for unserializing 'Mock_TokenInterface_278f77bc' in /usr/share/php/PHPUnit/Framework/MockObject/Generator.php on line 247
PHP Stack trace:
PHP 1. {main}() /usr/bin/phpunit:0
PHP 2. PHPUnit_TextUI_Command::main($exit = *uninitialized*) /usr/bin/phpunit:46
PHP 3. PHPUnit_TextUI_Command->run($argv = array (0 => '/usr/bin/phpunit'), $exit = TRUE) /usr/share/php/PHPUnit/TextUI/Command.php:129
PHP 4. PHPUnit_TextUI_Command->handleArguments($argv = array (0 => '/usr/bin/phpunit')) /usr/share/php/PHPUnit/TextUI/Command.php:138
PHP 5. PHPUnit_Util_Configuration->getTestSuiteConfiguration($testSuiteFilter = NULL) /usr/share/php/PHPUnit/TextUI/Command.php:657
PHP 6. PHPUnit_Util_Configuration->getTestSuite($testSuiteNode = class DOMElement { public $tagName = 'testsuite'; public $schemaTypeInfo = NULL; public $nodeName = 'testsuite'; public $nodeValue = '\n ./Tests\n '; public $nodeType = 1; public $parentNode = '(object value omitted)'; public $childNodes = '(object value omitted)'; public $firstChild = '(object value omitted)'; public $lastChild = '(object value omitted)'; public $previousSibling = '(object value omitted)'; public $nextSibling = '(object value omitted)'; public $attributes = '(object value omitted)'; public $ownerDocument = '(object value omitted)'; public $namespaceURI = NULL; public $prefix = ''; public $localName = 'testsuite'; public $baseURI = '/home/felicitus/repos/EscapeWSSEAuthenticationBundle/phpunit.xml.dist'; public $textContent = '\n ./Tests\n ' }, $testSuiteFilter = NULL) /usr/share/php/PHPUnit/Util/Configuration.php:776
PHP 7. PHPUnit_Framework_TestSuite->addTestFiles($filenames = array (0 => '/home/felicitus/repos/EscapeWSSEAuthenticationBundle/Tests/DependencyInjection/Security/Factory/FactoryTest.php', 1 => '/home/felicitus/repos/EscapeWSSEAuthenticationBundle/Tests/Security/Core/Authentication/Provider/ProviderTest.php', 2 => '/home/felicitus/repos/EscapeWSSEAuthenticationBundle/Tests/Security/Http/EntryPoint/EntryPointTest.php', 3 => '/home/felicitus/repos/EscapeWSSEAuthenticationBundle/Tests/Security/Http/Firewall/ListenerTest.php')) /usr/share/php/PHPUnit/Util/Configuration.php:860
PHP 8. PHPUnit_Framework_TestSuite->addTestFile($filename = '/home/felicitus/repos/EscapeWSSEAuthenticationBundle/Tests/Security/Core/Authentication/Provider/ProviderTest.php', $phptOptions = *uninitialized*) /usr/share/php/PHPUnit/Framework/TestSuite.php:416
PHP 9. PHPUnit_Framework_TestSuite->addTestSuite($testClass = class ReflectionClass { public $name = 'Escape\\WSSEAuthenticationBundle\\Tests\\Security\\Core\\Authentication\\Provider\\ProviderTest' }) /usr/share/php/PHPUnit/Framework/TestSuite.php:389
PHP 10. PHPUnit_Framework_TestSuite->__construct($theClass = class ReflectionClass { public $name = 'Escape\\WSSEAuthenticationBundle\\Tests\\Security\\Core\\Authentication\\Provider\\ProviderTest' }, $name = *uninitialized*) /usr/share/php/PHPUnit/Framework/TestSuite.php:315
PHP 11. PHPUnit_Framework_TestSuite->addTestMethod($class = class ReflectionClass { public $name = 'Escape\\WSSEAuthenticationBundle\\Tests\\Security\\Core\\Authentication\\Provider\\ProviderTest' }, $method = class ReflectionMethod { public $name = 'supports'; public $class = 'Escape\\WSSEAuthenticationBundle\\Tests\\Security\\Core\\Authentication\\Provider\\ProviderTest' }) /usr/share/php/PHPUnit/Framework/TestSuite.php:212
PHP 12. PHPUnit_Framework_TestSuite::createTest($theClass = class ReflectionClass { public $name = 'Escape\\WSSEAuthenticationBundle\\Tests\\Security\\Core\\Authentication\\Provider\\ProviderTest' }, $name = 'supports') /usr/share/php/PHPUnit/Framework/TestSuite.php:834
PHP 13. PHPUnit_Util_Test::getProvidedData($className = 'Escape\\WSSEAuthenticationBundle\\Tests\\Security\\Core\\Authentication\\Provider\\ProviderTest', $methodName = 'supports') /usr/share/php/PHPUnit/Framework/TestSuite.php:481
PHP 14. ReflectionMethod->invoke(class Escape\WSSEAuthenticationBundle\Tests\Security\Core\Authentication\Provider\ProviderTest { private $userProvider = NULL; private $providerKey = NULL; private $encoder = NULL; private $user = NULL; private $nonceCache = NULL; protected $backupGlobals = NULL; protected $backupGlobalsBlacklist = array (); protected $backupStaticAttributes = NULL; protected $backupStaticAttributesBlacklist = array (); protected $runTestInSeparateProcess = NULL; protected $preserveGlobalState = TRUE; private ${PHPUnit_Framework_TestCase}:inIsolation = FALSE; private ${PHPUnit_Framework_TestCase}:data = array (); private ${PHPUnit_Framework_TestCase}:dataName = ''; private ${PHPUnit_Framework_TestCase}:useErrorHandler = NULL; private ${PHPUnit_Framework_TestCase}:useOutputBuffering = NULL; private ${PHPUnit_Framework_TestCase}:expectedException = NULL; private ${PHPUnit_Framework_TestCase}:expectedExceptionMessage = ''; private ${PHPUnit_Framework_TestCase}:expectedExceptionCode = NULL; private ${PHPUnit_Framework_TestCase}:required = array ('PHP' => NULL, 'PHPUnit' => NULL, 'functions' => array (...), 'extensions' => array (...)); private ${PHPUnit_Framework_TestCase}:name = NULL; private ${PHPUnit_Framework_TestCase}:dependencies = array (); private ${PHPUnit_Framework_TestCase}:dependencyInput = array (); private ${PHPUnit_Framework_TestCase}:iniSettings = array (); private ${PHPUnit_Framework_TestCase}:locale = array (); private ${PHPUnit_Framework_TestCase}:mockObjects = array (); private ${PHPUnit_Framework_TestCase}:status = NULL; private ${PHPUnit_Framework_TestCase}:statusMessage = ''; private ${PHPUnit_Framework_TestCase}:numAssertions = 0; private ${PHPUnit_Framework_TestCase}:result = NULL; private ${PHPUnit_Framework_TestCase}:testResult = NULL; private ${PHPUnit_Framework_TestCase}:output = ''; private ${PHPUnit_Framework_TestCase}:outputExpectedRegex = NULL; private ${PHPUnit_Framework_TestCase}:outputExpectedString = NULL; private ${PHPUnit_Framework_TestCase}:hasPerformedExpectationsOnOutput = FALSE; private ${PHPUnit_Framework_TestCase}:outputCallback = FALSE; private ${PHPUnit_Framework_TestCase}:outputBufferingActive = FALSE }) /usr/share/php/PHPUnit/Util/Test.php:262
PHP 15. Escape\WSSEAuthenticationBundle\Tests\Security\Core\Authentication\Provider\ProviderTest->providerSupports() /usr/share/php/PHPUnit/Util/Test.php:262
PHP 16. PHPUnit_Framework_TestCase->getMock($originalClassName = 'Symfony\\Component\\Security\\Core\\Authentication\\Token\\TokenInterface', $methods = *uninitialized*, $arguments = *uninitialized*, $mockClassName = *uninitialized*, $callOriginalConstructor = *uninitialized*, $callOriginalClone = *uninitialized*, $callAutoload = *uninitialized*, $cloneArguments = *uninitialized*) /home/felicitus/repos/EscapeWSSEAuthenticationBundle/Tests/Security/Core/Authentication/Provider/ProviderTest.php:98
PHP 17. PHPUnit_Framework_MockObject_Generator::getMock($originalClassName = 'Symfony\\Component\\Security\\Core\\Authentication\\Token\\TokenInterface', $methods = array (), $arguments = array (), $mockClassName = '', $callOriginalConstructor = TRUE, $callOriginalClone = TRUE, $callAutoload = TRUE, $cloneArguments = FALSE) /usr/share/php/PHPUnit/Framework/TestCase.php:1318
PHP 18. PHPUnit_Framework_MockObject_Generator::getObject($code = 'class Mock_TokenInterface_278f77bc implements PHPUnit_Framework_MockObject_MockObject, Symfony\\Component\\Security\\Core\\Authentication\\Token\\TokenInterface\n{\n private static $__phpunit_staticInvocationMocker;\n private $__phpunit_invocationMocker;\n\n public function __clone()\n {\n $this->__phpunit_invocationMocker = clone $this->__phpunit_getInvocationMocker();\n }\n\n public function __toString()\n {\n $arguments = array();\n $count = func_num_args();\...', $className = 'Mock_TokenInterface_278f77bc', $originalClassName = 'Symfony\\Component\\Security\\Core\\Authentication\\Token\\TokenInterface', $callOriginalConstructor = TRUE, $callAutoload = TRUE, $arguments = array ()) /usr/share/php/PHPUnit/Framework/MockObject/Generator.php:216
PHP 19. unserialize('O:28:"Mock_TokenInterface_278f77bc":0:{}') /usr/share/php/PHPUnit/Framework/MockObject/Generator.php:247
Warning: Erroneous data format for unserializing 'Mock_TokenInterface_278f77bc' in /usr/share/php/PHPUnit/Framework/MockObject/Generator.php on line 247
Hi There
I wonder if there's a possibility to properly use the WSSE bundle with sha1 encoded passwords (as opposed to plaintext) in symfony2. We're currently using the FOSUserBundle, and with this configuration
encoders:
FOS\UserBundle\Model\UserInterface: sha512
the WSSE authentication does not seem to work. However, using
encoders:
FOS\UserBundle\Model\UserInterface: plaintext
and sending a plaintext password when creating the token, works fine.
Any ideas?
I am using the EscapeWSSEAuthenticationBundle with the FOSUserBundle as a provider.
Since updating from dev-master a06e4dd to dev-master 0454e35 i cannot authenticate. The log file says: app.DEBUG: WSSE authentication failed.
Before the composer update it was working fine. Any ideas what change between the two version could have such an impact?
Fixing the composer version to "escapestudios/wsse-authentication-bundle": "dev-master##a06e4dd" helps.
My security.yml is (regarding WSSE) as described on the readme page.
I compared the source code between the versions and found a change in the signature:
protected function validateDigest($digest, $nonce, $created, $secret, $salt)
How do i have to modify my code so that it works with the new WSSE version?
How about abstracting the storage for a nonces?
This way other storages can be implemented, even by the user fitting for their needs.
I was just reviewing #19 and #44 and the problem of clearing old cache entries.
One problem with Doctrine cache (and it appears most cache libraries I looked at) is that there's no support for cache "bins". Seems like that would help since we'd create a bin for "wsse_nonces", and just deal with clearing that bin as needed.
It still doesn't help with clearing cache entries that are expired. It's not clear to me after reading Doctrines cache documentation how you would clear expired entries, or how Doctrine itself clears them for things like query cache.
But beyond all of that, is using a cache really appropriate for storing nonces? Caches should be able to be cleared and not really affect functionality, only performance. But if for whatever reason the whole nonce cache is dropped, there's a brief security hole in the app since a replay attack could now succeed.
Just wanted to use this thread to get my thoughts down and start a discussion.
I don't typically like to include @dev releases in a project, but it seems like there is no actual release for the 2.3 branch. Can you please release a version for this branch? Otherwise when running composer update I will bring in potentially unstable commits for this code. Thanks
Right now I've successfully setup my WSSE Authentication using your bundle.
I get a token from
POST /security/create_token.json with the username and password sent over SLL
This returns a X-WSSE header which I use in my AngularJS application.
Using that X-WSSE header I can now do a
GET /api/v1/friends with the X-WSSE header I just received in the request header
The problem is that for every request I have to do I have to ask a new token from the /security/create_token.json service which causes a lot of overhead.
Isn't there a way to reuse the successfully created token I had the first time until I invalidate it by going to /security/destroy_token.json or by a lifetime settings in security.yml?
I'd like a similar functionality like OAuth where you generate a token and you can use that token for for example 60 days or until you manually invalidate the token.
I already have a mechanism in AngularJS where I send the X-WSSE header with every request but the problem is that I get a "previously used nonce detected" error if I try to reuse the token for a follow up request.
Any suggestions @djoos ?
Hello !
I have a strange behavior with WSSE Authentication with this bundle. With Firefox and Chrome browser at Ubuntu operating-system every thing works fine. But If I try to access my Rest API with a browser under Windows (Firefox or Chrome - same version as under Ubuntu) I get "401 unauthorized" response.
Maybe someone has an idea where to look at to solve this ?
Thanks in advance.
PHP strtotime
not only can parse a date but also some words to make time, like.. "now". When you don't cache and validate nonces it is possible to create a token which never expires and is always valid. You have to just create a token with "now" as "created" param. :)
I've tried to install it using the composer command:
php composer.phar update escapestudios/wsse-authentication-bundle
I've got no error but when trying to call a webservice, after adding it to AppKernerl I got the error
Fatal error: Class 'Escape\WSSEAuthenticationBundle\EscapeWSSEAuthenticationBundle' not found in /var/www/sample/public_html/app/AppKernel.php
I have been struggling to implement a working client. I'm trying to implement a client where the user enters his username and password and it's used to create the digest for each wsse request.
The problem is that the password is encoded and salted in the database (I user fosuserbundle to handle users). The one entered by the user is plain.
When I compare the digests it never works. The one generated on the clien side uses plain password,
the one build on the server uses the encoded and salted password.
I havent't been able to figure out how to build the proper digest on the client's side. The client has no information on how the password is encoded and can not retrieve the password's salt.
Can anyone help me?
Hi @djoos , I have this easy code
callAction();
function callAction()
{
$content= curl_download('http://sym2_pay_gateway.dev/api/doc', generate_wsse_header('app_53b14441d854d', 'f73ea3026372fbdafdcaefd8d79249efa530470a'));
echo $content;
die;
}
function generate_wsse_header($username, $secret)
{
// date_default_timezone_set('Europe/Paris');
$nonce = md5(rand(), true);
$created = date(DATE_ATOM);
$digest = base64_encode(sha1($nonce.$created.$secret,true));
$b64nonce = base64_encode($nonce);
return sprintf('X-WSSE: UsernameToken Username="%s", PasswordDigest="%s", Nonce="%s", Created="%s"',
$username,
$digest,
$b64nonce,
$created
);
}
function curl_download($Url, $header){
// is cURL installed yet?
if (!function_exists('curl_init')){
die('Sorry cURL is not installed!');
}
// OK cool - then let's create a new cURL resource handle
$ch = curl_init();
// Now set some options (most are optional)
// Set URL to download
curl_setopt($ch, CURLOPT_URL, $Url);
// Set a referer
curl_setopt($ch, CURLOPT_REFERER, "http://www.example.org/yay.htm");
// User agent
curl_setopt($ch, CURLOPT_USERAGENT, "MozillaXYZ/1.0");
// Include header in result? (0 = yes, 1 = no)
curl_setopt($ch, CURLOPT_HEADER,0 );
// Should cURL return or print out the data? (true = return, false = print)
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
// Timeout in seconds
curl_setopt($ch, CURLOPT_TIMEOUT, 10);
//curl_setopt ($ch, CURLOPT_FOLLOWLOCATION, 1);
// Header
curl_setopt($ch, CURLOPT_HTTPHEADER, array($header));
// Download the given URL, and return output
$output = curl_exec($ch);
// Close the cURL resource, and free system resources
curl_close($ch);
return $output;
}
but i get this
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<meta http-equiv="refresh" content="1;url=http://sym2_pay_gateway.dev/api/doc/" />
<title>Redirecting to http://sym2_pay_gateway.dev/api/doc/</title>
</head>
<body>
Redirecting to <a href="http://sym2_pay_gateway.dev/api/doc/">http://sym2_pay_gateway.dev/api/doc/</a>.
</body>
</html>
In postman it works perfectly but by curl it doesn`t. Sorry for this dummy question :_
Error msg:
Unrecognized options "realm, profile, lifetime, encoder" under "security.firewalls.wsse_secured.wsse"
Symfony verion is last
Files:
https://gist.github.com/jonatasfreitasv/8f61799d8c3697b5259c
Thx a lot.
If the user provided doesn't exist the bundle displays a message advertising that the given user doesn't exists in the system so it is an information disclosure vulnerability
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.