symony 3.3 guard authetication with multiple providers - authentication

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

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

Forgot password in .Net Core 5.0

my login and register methods are working well and i use the Claim when the user try to login or logout.
i saw many example of that ForgotMyPassword page but all of it using
private readonly UserManager<IdentityUser> _userManager; which is based on Microsoft.AspNetCore.Identity; . Can i do ForgotMyPassword action without using UserManager
?? im asking that Claim based authentication and authorization is what i need in my project.
can i use them both,if i can how can i do that ?
it would be so great if someone explain its clearly,regards
When users register, their information will be added to the database. You can pass the registered email of the user to the ForgotMyPassword action. Then send a verification code to the mailbox or send a link to make user redirect to another page to reset the password. Make the user finish changing the password.
You can both use authentication and authorization, they are responsible for different businesses. Authentication has cookie, jwt and other authentication service. cookie authentication is the built-in component. Identity has integrated it. You should have learn about it.
The another service is authorization. Authorization service only works after authentication is successful. It has many authorization methods, about claim-based authorization, when one user access the authorized action, it will go through the middleware app.UseAuthorization(). This middleware will check whether there is a claim corresponding to the action policy's claim. Because you have configured it in startup.
services.AddAuthorization(options=>
{
options.AddPolicy("Policy1",policy=>
{
policy.RequireClaim("claim1",new string[] {"value1","value2" });
});
});
On the authorized action.
[Authorize(Policy = "Policy1")]
public IActionResult get()
{
return Ok();
}
In this scenario, the user should have the claim Claim("claim1","value1") or Claim("claim1","value2").

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

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.

Symfony2 OAuth2 login stuck in infinite redirect loop

I'm using the HWI OAuth Bundle to allow users to login with Google Apps. It allows the user to login as expected.
However, after about 5 minutes the cookie expires and it tries to redirect to /login, but it gets stuck in an infinite redirect loop. It's trying to load /login on port 443, but returning a 302 redirect to the same URL every time. If I clear the Symfony cache on the server, or clear cookies in the browser, it shows the login page and works again.
// security.yml:
firewalls:
secured_area:
anonymous: ~
oauth:
resource_owners:
google: "/login/check-google"
oauth_user_provider:
service: my.security.userprovider
login_path: /login/
failure_path: /login/
form_login:
login_path: /login/
logout:
path: /logout
target: /login/
access_control:
- { path: ^/(_(profiler|wdt)|css|images|js)/, role: IS_AUTHENTICATED_ANONYMOUSLY }
- { path: ^/, role: IS_AUTHENTICATED_ANONYMOUSLY }
- { path: ^/login, role: IS_AUTHENTICATED_ANONYMOUSLY }
- { path: ^/connect, role: IS_AUTHENTICATED_ANONYMOUSLY }
- { path: ^/, role: ROLE_STAFF, host: %cms% }
The urls are structured so that:
Everything on admin.example.com is secured
Everything on any other subdomain is public. Subdomains are generated dynamically.
There is nothing in the nginx, Symfony2 or FPM logs. I've put the same code on a different server in production environment, and the same thing happens. I can't work out whether it's the security bundle, the HWI OAuth bundle, or something in between.
So, question is which method is producing the redirect, and how do I stop it?
Worked it out. The first time a user logins in UserProvider::loadUserByOAuthUserResponse() receives a `UserResponse' that contains the email address of the user. I'm using this to load the user from my database.
However, every 5 minutes it checks the token against the OAuth provider again, by checking the user's access token (stored in the user's session). This time the UserResponse contains only the access token meaning the email address is null, so it can't find the user. This throws a UsernameNotFoundException exception, but HWIOAuthBundle doesn't catch it.
So, HWIOAuthBundle returns a null user object to the Authentication bundle, which then recognises the user needs to authenticate so redirects to login. Since the user already has an access token, it checks that against the OAuth provider, but again does not return email address, so the user can't be found, and it redirects to login. Hence the loop.
The fix - store the user's access token in the database, and try to load the user by access token.
This gist was particularly useful in seeing how to build a working UserProvider.

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.