How to manage two authentications systems: with and without state (cache) - api

I have an HTTP API using Symfony 3.
I am using GuardAuthenticator, so that we can call the API, using a login and password, with stateless (security attribute) set to false.
Today I add another way of authenticate, by using jwt from an external IDP. In this case, I would like to have statless set to true (the user will have to provide the jwt at every call).
Do you have any ideas please ? :)
api:
pattern: ^/api/
stateless: false
guard:
authenticators:
- api.security.guard_authenticator
switch_user: true
anonymous: ~

in my API I have a Basic Auth + Token system. To do so, in the pre_auth I had a check for the BasicAuth.
I Guess if you passing the stateless to true, you'll have to implements something similar.

Related

Symfony, security.yaml : using both form and token authentication for same uri

My Symfony 5 app provides:
api endpoints like api/entry/get/1 (secured with oauth2)
admin pages like users/list (secured with database user provider)
For this purpose, my security.yaml uses two firewalls:
firewalls:
api:
pattern: ^/api(?!/doc$)
security: true
stateless: true
oauth2: true
main:
lazy: true
provider: app_user_provider
form_login:
login_path: app_login
check_path: app_login
enable_csrf: true
default_target_path: app_index
use_referer: true
logout:
path: app_logout
target: app_index
Is this possible to also access api endpoints like api/entry/get/1 when connected as an admin (ie not with a token but through regular form login with credentials) ?
This would make using a swagger sandbox much easier.
Is this possible to also access api endpoints like api/entry/get/1 when connected as an admin (ie not with a token but through regular form login with credentials) ?
I'd say in your current configuration, the answer is no.
Since you api firewall is sateless: true there's only one way to tell symfony that request should be considered as authenticated. The presence of Bearer token (it's probably a JWT) in each request. Without a valid token, all request to /api would be considered as unauthorized
In other words: symfony just do not check session/cookies for possible (previously) logged in (admin) user to allow/deny access for all /api routes.
Unfortunately, I hadn't an opportunity to work with OAuth2ServerBundle. So maybe there's a configuration for that.
BUT:
Try to play around with staless and context
about stateless
about context
However, RESTful APIs are stateless by design, it's not just a fancy buzzword.
There is also a way to add "Authorize" button to your swagger doc/playgroung so anyone who has access to swaggerUI, could paste a valid auth-token (JWT) and all further request from swaggerUI would be authorized. See Swagger and JWT Token Authentication
I also had a wonderful experience with Insomnia http-client especially when I need to test/play with my apis.
It has great OAuth v.2 support. Free tier is more than enough for local development / quick testing. Just specify your token path, select GrantType as "Resource Owner" paste username/password of your admin user and insomnia will handle the rest automagically each time you hit a protected /api/entry/get/1

Symfony rest api error with security.yaml

I'm trying to add an auth system with JWT to my REST API but since I added my system and modified my security.yaml I have those errors:
make sure of the alignments .. it can be spaces problem
api:
pattern: ^/api
guard:
authenticators:
Lexik bundle doesn't require anymore guard with symfony 6

symony 3.3 guard authetication with multiple providers

I am implementing a symfony (3.3) custom guard authenticator to authenticate a user against OKTA and it's working fine without any issues.
However, I'd like to authenticate an admin user against the credentials stored in the database.
Basically, if any user hits /api/login endpoint it should authenticate against OKTA, except for one admin user who should be authenticated against the password stored in the database. How can I achieve this pls?
Here is my security.yml
security:
providers:
db_user_provider:
entity:
class: MyApiBundle:ApiUser
property: username
okta_user_provider:
id: okta_user_provider
my_chain_provider:
chain:
providers:
- db_user_provider
- okta_user_provider
firewalls:
login:
pattern: ^/api/login
anonymous: true
stateless: true
provider: my_chain_provider
guard:
authenticators:
- authenticator_guard_okta
Many thanks
I solved this issue in my custom LoginFormAuthenticator
i.e in
public function getUser($credentials, UserProviderInterface $userProvider)
A) check if the $credentials['username'] exist in db. If yes, find the user entity from db and return the user
B) check if the $credentials['username'] exist in okta. If yes, load the user from okta and return the user
public function checkCredentials($credentials, UserInterface $user)
A) check if the user is an instance of db user entity. If yes, validate the password and return the user
B) check if the user is an instance of okta user. If yes, validate against okta and return okta user

Symfony2.1 - HWIOAuthBundle and google oauth authentication

I am trying to setup Symfony2.1 with HWIOAuthBundle to handle google oauth authentication.
I have followed manual instructions in bundle description, but still something is missing. When I visit an action which requires authenticated user (or just type url /connect/google) I am redirected to google authentication page - this part is working. But after redirection back (after logging to Google and agree for sharing my data) new user is not created in DB and I am redirected into connect/fail action. Google authentication should be only one way to authenticate user. Any idea what could be wrong?
This is my routing:
hwi_oauth_redirect:
resource: "#HWIOAuthBundle/Resources/config/routing/redirect.xml"
prefix: /connect
google_login:
pattern: /login/check-google
security.yml
firewalls:
dev:
pattern: ^/(_(profiler|wdt)|css|images|js)/
security: false
secured_area:
pattern: ^/
form_login:
provider: fos_userbundle
login_path: /connect/google
check_path: /login/login_check
logout: true
anonymous: true
oauth:
resource_owners:
google: "/login/check-google"
login_path: /connect/google
failure_path: /connect-fail
# FOSUB integration
oauth_user_provider:
service: hwi_oauth.user.provider.fosub_bridge
and config
hwi_oauth:
firewall_name: secured_area
resource_owners:
google:
type: google
client_id: ....
client_secret: ......
scope: "https://www.googleapis.com/auth/userinfo.email https://www.googleapis.com/auth/userinfo.profile"
fosub:
username_iterations: 5
properties:
google: googleId
google redirectURL
http://xxxx/login/check-google
my User entity:
class User extends BaseUser
{
/**
* #var integer $id
*
* #ORM\Column(name="id", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
protected $id;
/**
* #var integer $id
*
* #ORM\Column(name="google_id", type="integer")
*/
protected $googleId;
//edit- update
I just found in Symfony logs that I had one request from google redirect:
GET http://xxxxx.dk/login/check-google?code=4%2F8tiDAhI45D2g7BvrdtwoF7wJ.Eu7i2fmkYOl05ti8ZT3YDrXXXXXfakeXXXE4hcwI just before redirect to /connect-file
Unfortunately it looks that request only tried to retrieve user from my db based on google_id
SELECT * FROM app_user t0 WHERE t0.googleId = ? LIMIT 1 : ['123456789'] but that user does not exist there.
Should I create user befor I tryied to authenticate him/her?
As beliveyourdream says... HWIOAuth does NOT provide you automatic user registration. You need to create your own user provider and use that. I suggest you go with FOSUserBundle as it does most of the job and it is pretty well integrated in HWIOAuth. For how to set up (as it is a bit of work to do on connecting them), please use this Gist. It does setup your application with both user registration using data from PROVIDERS (gacebook, google, github, etc.) and account connection (an already registered user may connect his/her account with accouns from PROVIDERS). Also, upon creation/connection, the users will be able to connect to your site with the PROVIDERS' credentials (duh... it's OAuth, after all).
Sadly, HWIOAuthBundle doesn't handle automatic registration by default. If you want to login now you'll have to create the user manually.

Authentication for a Symfony2 api (for mobile app use)

I've developed a REST api for my Symfony2 application. This api will be used by a mobile app. Much of the functionality is done in the context of the currently authenticated user, ie:
$this->container->get('security.context')->getToken()->getUser()
I'm hoping that the mobile app will be able to post to the login action just like a traditional web form. If the credentials check out then Symfony2 does it's thing and sets a cookie (does this even work in the context of a mobile app accessing an api?). Then later api requests from that mobile phone will (hopefully) work with the native symfony2 security.context service container.
Would this work? I need to figure out this authorization process before I take the API to the mobile developers. If possible I'd obviously like to be able to use the native security.context service instead of building out a new auth system for the api that uses xAuth or something similar.
Thanks
I think you should do it stateless (without cookie).
I had the same problem, what i did:
in your app/config/security.yml, add:
security:
...
firewalls:
rest_webservice:
pattern: /webservice/rest/.*
stateless: true
http_basic:
provider: provider_name
...
Now you can make a request to your webservice:
class AuthTest extends WebTestCase
{
public function testAuthenticatedWithWebservice()
{
$client = $this->createClient();
// not authenticated
$client->request('GET', '/webservice/rest/url');
$this->assertEquals(401, $client->getResponse()->getStatusCode());
// authenticated
$client->request('GET', '/webservice/rest/url', array(), array(), array(
'PHP_AUTH_USER' => 'username',
'PHP_AUTH_PW' => 'password'
));
$this->assertEquals(200, $client->getResponse()->getStatusCode());
}
}
Here you are, How to create a custom Authentication Provider awesome article.
To Authentication to a Symfony2 application through api, you need use:
WS-Security
Yes Marc, jules is pointing to an example just to show you how to test authentication with http_basic.
To be RESTful you should avoid using cookies, otherwise just call it an API. About how secure is your authentication system you can go with http_digest over https or more secure signed request with api_key/api_secret approach.
Have a look here http://wiki.zanox.com/en/RESTful_API_authentication