Symfony FOS user bundle - Switch User failed: "Username "*" does not exist." - fosuserbundle

It really is what the headline states - I can't figure out why user switching isn't working.
In my security.yml I have:
firewalls:
# disables authentication for assets and the profiler, adapt it according to your needs
dev:
pattern: ^/(_(profiler|wdt)|css|images|js)/
security: false
main:
pattern: ^/
form_login:
provider: fos_userbundle # using FOSUserBundle for user authentication
check_path: fos_user_security_check
login_path: fos_user_security_login
csrf_token_generator: security.csrf.token_manager # CSRF token - can be changed?
default_target_path: default_logged_in_target # default route to go to after login
# default_target_path: fos_user_profile_show
always_use_default_target_path: true # ignore the requested url and allways go to default route after login
logout:
path: fos_user_security_logout
target: default_loged_out_target
logout: true
anonymous: true
switch_user: true
Calling the URL
[ProjectPath]/account?_switch_user=testuser
results in the error
Switch User failed: "Username "testuser" does not exist."
"testuser" however is a perfectly valid user and I can log in normaly with that user when logging in the standard way.
The user I am logged in with when calling the URL with "_switch_user" does have the role "ROLE_ALLOWED_TO_SWITCH" - however this doesn't seem to be the problem.
I am stuck here.
Any hints are highly appreciated.
EDIT:
The stacktrace shows that in "SwitchUserListener.php" the call to
$this->tokenStorage->setToken($this->attemptSwitchUser($request));
fails and is catched resulting in the given error.

I could get it to work adding the fos_userbundle user provider to security.yml like this:
firewalls:
..
main:
...
switch_user:
provider: fos_userbundle

Ok, I made a stupid mistake, but perhaps someone else did as well. I use email for authenticating, but used the username for switching the user. Make sure you use the same property. So in my case I needed to use the email:
?_switch_user=example#email.com

Related

Losing Auth when navigating to different part of page-RoR, React

This is my first ever question.
I'm using react/vite and Rails 7 to build a firehouse management web app. I originally set up rails as an api with --api. Right now, I can log in but when the user clicks home, or any other link on the page, I loose the authorization(or thats what I'm thinking). I'm using the Bcrypt gem. The console.log(user) on my other pages is returning null, but on the inital login it returns the user object. Now, I have another issue with the logging in all together.
I'm getting a 422 'Unprocessable entity' where my request.base_url doesnt match the localhost:3000. I'm assuming thats because vite is running on 5173?
Here is the error
{status: 422, error: 'Unprocessable Entity', exception: '#<ActionController::InvalidAuthenticityToken: HTTP…t match request.base_url (http://localhost:3000)>', traces: {…}}
error
:
"Unprocessable Entity"
exception
:
"#<ActionController::InvalidAuthenticityToken: HTTP Origin header (http://127.0.0.1:5173) didn't match request.base_url (http://localhost:3000)>"
status
:
422
puma.rb
# Specifies the `port` that Puma will listen on to receive requests; default is 3000.
#
port ENV.fetch("PORT") { 3000 }
# Specifies the `environment` that Puma will run in.
#
environment ENV.fetch("RAILS_ENV") { "development" }
# Specifies the `pidfile` that Puma will use.
pidfile ENV.fetch("PIDFILE") { "tmp/pids/server.pid" }
I tried to convert rails to the full framework because I thought it was something with the session and cookies. I added a cookie serializer and a session_store.
application.rb
class Application < Rails::Application
# Adding cookies and session middleware
config.middleware.use ActionDispatch::Cookies
config.middleware.use ActionDispatch::Session::CookieStore
config.api_only = false
# Initialize configuration defaults for originally generated Rails version.
config.load_defaults 7.0
# This will allow any origin to make requests to any resource on your server, using any HTTP method.
config.middleware.insert_before 0, Rack::Cors do
allow do
origins '*'
resource '*',
headers: :any,
methods: %i[get post put patch delete options head]
end
end
end
end
cookie_serializer.rb
Rails.application.config.action_dispatch.cookies_serializer = :hybrid
session_store.rb
if Rails.env === 'production'
Rails.application.config.session_store :cookie_store, key: '_fire-sphere', domain: '_fire-sphere-json-api'
else
Rails.application.config.session_store :cookie_store, key: '_fire-sphere'
end
Here is my application_controller.rb
class ApplicationController < ActionController::Base
include ActionController::Cookies
rescue_from ActiveRecord::RecordNotFound, with: :render_not_found
rescue_from ActiveRecord::RecordInvalid, with: :render_unprocessable_entity
def authorized
return render json: {error: "Not Authorized"}, status: :unauthorized unless session.include? :current_user
end
private
def render_unprocessable_entity(invalid)
render json: {errors: invalid.record.errors.full_messages}, status: :unprocessable_entity
end
def render_not_found(error)
# byebug
render json: {error: "#{error.model} Not Found"}, status: :not_found
end
end
show method in users_controller.rb
def show
# using session to find user in question. sessions are in user browser
# if session for user currently happening, set our user to that user and render json
# byebug
current_user = User.find_by(id: session[:current_user])
render json: current_user
end
I think somehow the user isn't getting stored in the session. I was able to check the params on my initial problem and the user was in there but not when I navigated away. I think I've shnaged somthething somewhere and caused a whole other problem now. Thank you for taking a look! I hope it is something simple..

Gitlab Authentication returns invalid username or password (LDAP pane missing)

I have users in active directory LDAP (each have a username and email set).
I configured LDAP authentication in gitlab.rb and ran "gitlab-ctl reconfigure".
I user Gitlab Community Edition.
The following command returns the users so configuration seems ok "sudo gitlab-rake gitlab:ldap:check".
Returns :
LDAP: ... Server: ldapmain
LDAP authentication... Success
LDAP users with access to your GitLab server (only showing the first 100 results)
DN: cn=Mike Gordon,cn=users,dc=ad,dc=mydomain,dc=com sAMAccountName: mike.gordon
... here other users
I'm trying to login with LDAP username mike.gordon and corresponding password on "Sign in" gitlab pane but i get "invalid username or password".
Some screenshots show that there is an LDAP pane but it's not displayed even with :
gitlab_rails['prevent_ldap_sign_in'] = false
this is my configuration :
main: # 'main' is the GitLab 'provider ID' of this LDAP server
label: 'LDAP'
host: 'myAdUrl'
port: 3268
uid: 'sAMAccountName'
bind_dn: 'CN=serveur-ovh,CN=Users,dc=ad,dc=mydomain,dc=com'
password: 'adpassword'
encryption: 'plain' # "start_tls" or "simple_tls" or "plain"
active_directory: true
allow_username_or_email_login: false
base: 'dc=ad,dc=mydomain,dc=com'
user_filter: ''
#lowercase_usernames: false
#block_auto_created_users: false
#verify_certificates: true
#smartcard_auth: false
### EE only
Thank you very much in advance for you help.
Comparing your configuration to mine, I have a user_filter value
###! **remember to close this block with 'EOS' below**
gitlab_rails['ldap_servers'] = YAML.load <<-'EOS'
main: # 'main' is the GitLab 'provider ID' of this LDAP server
label: 'LDAP'
host: 'ADHostname.example.com'
port: 636
uid: 'sAMAccountName'
method: 'ssl' # "tls" or "ssl" or "plain"
bind_dn: 'cn=UserID,ou=SystemAccounts,dc=example,dc=com'
password: 'AccountPasswordGoesHere'
active_directory: true
allow_username_or_email_login: false
block_auto_created_users: false
base: 'ou=ResourceUsers,dc=example,dc=com'
user_filter: '(&(sAMAccountName=*))' # Can add attribute value to restrict authorized users to GitLab access, we leave open to all valid user accounts in the OU. Should be able to authorize based on group membership using linked attribute value like (&(memberOf=cn=group,ou=groupOU,dc=example,dc=com))
attributes:
username: ['uid', 'userid', 'sAMAccountName']
email: ['mail', 'email', 'userPrincipalName']
name: 'cn'
first_name: 'givenName'
last_name: 'sn'
EOS

Allowing "regular" users access to Sonata Admin CRUD actions

hope someone can steer me in the right direction!
I'm setting up a SonataAdmin based system for a project I'm working on that utilizes the SonataUserBundle.
I have a model setup extending AbstractMain for CRUD actions which is accessible using the navigation menu. From here, as a super admin, I can list, create, edit and delete items. Perfect!
My aim is to use the same SonataAdmin portal for 'subscribed' users, but with limited access. They should only be able to list items. However, I'm at something of a loss when it comes to just how to configure the symfony / sonata / fosuser security & firewall rules going on under the hood to make this happen.
My app/config/security.yml is as such.
security:
role_hierarchy:
ROLE_ADMIN: [ROLE_USER, ROLE_SONATA_ADMIN]
ROLE_SUPER_ADMIN: [ROLE_ADMIN, ROLE_ALLOWED_TO_SWITCH]
SONATA:
# - ROLE_SONATA_PAGE_ADMIN_PAGE_EDIT # if you are using acl then this line must be commented
encoders:
FOS\UserBundle\Model\UserInterface: sha512
acl:
provider: mongodb_acl_provider
# https://symfony.com/doc/current/security.html#b-configuring-how-users-are-loaded
providers:
fos_userbundle:
id: fos_user.user_provider.username
hwi:
id: sonata_oauth2_login.user.provider
firewalls:
# disables authentication for assets and the profiler, adapt it according to your needs
dev:
pattern: ^/(_(profiler|wdt)|css|images|js)/
security: false
admin:
# #pattern: /admin(.*) #REMOVE THIS LINE IF YOU ARE USING SONATA ADMIN
context: user
form_login:
provider: fos_userbundle
login_path: /portal/login
use_forward: false
check_path: /portal/login_check
failure_path: null
always_use_default_target_path: false
default_target_path: /portal/dashboard
logout:
path: /portal/logout
target: /portal/login
anonymous: true
oauth:
resource_owners:
google: "/login/check-google"
facebook: "/login/check-facebook"
login_path: /portal/login # For Sonata Admin
use_forward: false
default_target_path: /portal/dashboard # For Sonata Admin
failure_path: /portal/login # For Sonata Admin
oauth_user_provider:
service: sonata_oauth2_login.user.provider
access_control:
# Admin login page needs to be accessed without credential
- { path: ^/portal/login$, role: IS_AUTHENTICATED_ANONYMOUSLY }
- { path: ^/portal/logout$, role: IS_AUTHENTICATED_ANONYMOUSLY }
- { path: ^/portal/login_check$, role: IS_AUTHENTICATED_ANONYMOUSLY }
- { path: ^/portal/resetting, role: IS_AUTHENTICATED_ANONYMOUSLY }
# Secured part of the site
# This config requires being logged for the whole site and having the admin role for the admin part.
# Change these rules to adapt them to your needs
- { path: ^/portal/, role: [ROLE_ADMIN, ROLE_SONATA_ADMIN, ROLE_SONATA_USER] }
- { path: ^/.*, role: IS_AUTHENTICATED_ANONYMOUSLY }
services:
mongodb_acl_provider:
parent: doctrine_mongodb.odm.security.acl.provider
This is my sonata_admin config under config.yml:
sonata_admin:
title: BLAHBLAH
options:
title_mode: single_text
templates:
list: AppBundle:CRUD:list.html.twig
base_list_field: AppBundle:CRUD:base_list_field.html.twig
layout: AppBundle::standard_layout.html.twig
security:
handler: sonata.admin.security.handler.acl
# handler: sonata.admin.security.handler.role
role_admin: ROLE_ADMIN
role_super_admin: ROLE_SUPER_ADMIN
# acl security information
information:
GUEST: [VIEW, LIST]
STAFF: [EDIT, LIST, CREATE]
EDITOR: [OPERATOR, EXPORT]
ADMIN: [MASTER]
# permissions not related to an object instance and also to be available when objects do not exist
# the DELETE admin permission means the user is allowed to batch delete objects
admin_permissions: [CREATE, LIST, DELETE, UNDELETE, EXPORT, OPERATOR, MASTER]
# permission related to the objects
object_permissions: [VIEW, EDIT, DELETE, UNDELETE, OPERATOR, MASTER, OWNER]
Now, with this configuration, I can (as a superadmin) edit a user and grant the individual user through the ACL settings access to edit their own profile, as seen here:
ACL Settings for user
Nothing exists in the user settings for roles...
Roles for user
I've done what I can to follow along with the SonataUserBundle instructions for setting up security, but I'm falling short in understanding somewhere along the way.
In short, all users will be utilizing the same admin portal. Admins can create new users, products, etc. "Regular" users can edit their own profile and 'view' products from the admin class extended from AbstractAdmin by clicking the link in the menu on the left.
I feel like I'm wandering around Symfony security blindfolded right now with fosuserbundle & sonatauserbundle added to the mix. :(
This is my first post, so please forgive me if I'm missing anything important to include. I'll do my best to fill in any details and I appreciate your time observing my plight!

Symfony2: allow all unmatched routes to be accessed anonymously

I have Symfony2 application separated into 2 bundles: BackendBundle for API and FrontendBundle for AngularJS "client". Everything works under firewall.
BackendBundle has entities, handles API routes; FrontendBundle has Angular views, routing etc. and has only one controller with wildcard:
class AngularController extends Controller {
/**
* #Route("/{route}", name="angular_index_all_unmatched_routes", requirements={"route" = ".*"})
* #Template("FrontendBundle::index.html.twig")
*/
public function angularIndexAction($route) {
return ['route' => $route];
}
}
FrontendBundle routing is defined as last resource in app/config/routing.yml, to be invoked only if any other route was not matched. Thanks to that, it can handle Angular HTML5-mode routes if they're accessed directly (for example copy-paste) - and it works ok.
What I want to do, is define firewall and/or access control in way that all those unmatched routes (handled by AngularController::angularIndexAction()) could be accessible by anonymous user.
Why? I want to open some API routes (via frontend proxy) to be accessible by non-users (for example confirmation URLs sent by email, with some message to user).
I don't want to hardcode access control list for every anonymous "Angular" route, I would like to do it only for API routes. At the end, those unmatched routes should open Angular's index which should know if user is logged in (for displaying full or simplified layout) and should handle Angular routes and display some kind of "Access denied" message if request failed (there is Symfony listener and Angular's $provide interceptor for that).
Any suggestions?
Edit: #Security annotation on AngularController::angularIndexAction() does not work, it still redirects to firewall entry point.
Edit2: Here is fragment of security.yml
firewalls:
unsecured:
pattern: ^/(_(profiler|wdt)|css|images|js)/
security: false
anonymous: true
secured:
pattern: '^.*$'
form_login:
login_path: /our-provider/login
check_path: /our-provider/callback/
anonymous: true
entry_point: our_provider.entry_point
access_control:
- { path: '^/our-provider/(login(/[a-zA-Z]+)?|logout|redirect|callback)', roles: IS_AUTHENTICATED_ANONYMOUSLY }
- { path: '^/', roles: ROLE_USER }
I know that { path: '^/', roles: ROLE_USER } will redirect all routes to login page if user is not logged in. I assumed it's obvious and did not mentioned it. What I want is force ROLE_USER for matched routes and let IS_AUTHENTICATED_ANONYMOUSLY for those unmatched, without explicitely defining each frontend "proxy-route". In my case there is not 404 Symfony page, because everything goes to angular_index_all_unmatched_routes route and there Angular routing definition decides if there is something to handle or not.
I haven't tried this, and I cannot begin to guess your existing security/route setup in security.yml but I guess you could whitelist the method with IS_AUTHENTICATED_ANONYMOUSLY. From the Symfony docs:
All users (even anonymous ones) have this - this is useful when whitelisting URLs to guarantee access - some details are in How Does the Security access_control Work?.
So, for example, if you were using the #Security annotation you could do something like (not tested):
class AngularController extends Controller {
/**
* #Route("/{route}", name="route", requirements={"route" = ".*"})
* #Template("FrontendBundle::index.html.twig")
* #Security("has_role('IS_AUTHENTICATED_ANONYMOUSLY')")
*/
public function angularIndexAction($route) {
return ['route' => $route];
}
}
More on the #Security annotation here.
Hope this helps :)
Edit
All that said, when you define/restrict your routes under access_control in security.yml, the matching process stops on the first match. I assume that you have some role-restricted paths, which you should define explicitly - and put them first, so if they match the process stops.
Otherwise, you should be able to add a catch-all route, enforced by role IS_AUTHENTICATED_ANONYMOUSLY. Since the path definition of a route is a regex, something like ^/ should catch anything that is not explicitly defined. Just make sure and place it after your restricted route definitions.
You would not need for the #Security annotation in this case.
Edit 2
I tried mocking this out using a clean instance and HTTP BasicAuth but what I was trying to achieve was the following, which I understand as similar to your use case:
Create a backend controller with routes / and /api/ and trigger a HTTP BasicAuth authentication popup
Create a frontend controller with route /{route} that would match everything else and authenticate anonymously.
My firewall and access_control configuration looks like this:
security:
encoders:
# encoder config here
providers:
# provider config here
firewalls:
dev:
pattern: ^/(_(profiler|wdt)|css|images|js)/
security: false
secured:
anonymous: ~
http_basic: ~
access_control:
- { path: ^/$, roles: ROLE_USER }
- { path: ^/api/, roles: ROLE_USER }
- { path: ^/, roles: IS_AUTHENTICATED_ANONYMOUSLY }
Access control paths are regexes, so ^/$ and ^/ are not the same. The former will only match exactly to route /. The latter will match any route that begins with /; e.g: /home, /products, /contact etc.
Indeed, the latter will match and anonymously authenticate /api, but it will not match /api/, or /api/1 etc. as these are explicitly defined and restricted to ROLE_USER.
So the general idea is to explicitly and (if possible) exactly match the routes you want to restrict, and declare those first. The last declaration ^/ should openly catch any other route that falls through.

Gitlab Active Directory issues - gitlab-7.7.1_omnibus

I am having issues with Active Directory authentication via LDAP on Gitlab omnibus. I have tested the credentials and bind dn using ldapsearch and received a response with no issues, but for some reason I am not seeing any attempts at connecting when I login as an AD user on the gitlab frontend. I receive the error "Could not authorize you from Ldapmain because "Invalid credentials"." no matter if I'm using valid credentials or not.
I also receive the following from sudo gitlab-rake gitlab:check:
** Invoke gitlab:ldap:check (first_time)
** Invoke environment
** Execute gitlab:ldap:check
Checking LDAP ...
LDAP users with access to your GitLab server (only showing the first 100 results)
Server: ldapmain
Checking LDAP ... Finished
Please let me know if my explanation is not clear, or if you think that additional information would be helpful. I tried searching around and am not finding my exact issue.
My configuration is as follows:
gitlab_rails['ldap_enabled'] = true
gitlab_rails['ldap_servers'] = YAML.load <<-EOS # remember to close this block with 'EOS' below
main: # 'main' is the GitLab 'provider ID' of this LDAP server
## label
#
# A human-friendly name for your LDAP server. It is OK to change the label later,
# for instance if you find out it is too large to fit on the web page.
#
# Example: 'Paris' or 'Acme, Ltd.'
label: 'LDAP'
host: 'myadserver.my.domain.net'
port: 389
uid: 'sAMAccountName'
method: 'plain' # "tls" or "ssl" or "plain"
bind_dn: 'CN=Gitlab,OU=Service Accounts,OU=Washington\, D.C.,OU=United States,OU=NA,DC=my,DC=domain,DC=net'
password: 'mypasswrd'
# This setting specifies if LDAP server is Active Directory LDAP server.
# For non AD servers it skips the AD specific queries.
# If your LDAP server is not AD, set this to false.
active_directory: true
# If allow_username_or_email_login is enabled, GitLab will ignore everything
# after the first '#' in the LDAP username submitted by the user on login.
#
# Example:
# - the user enters 'jane.doe#example.com' and 'p#ssw0rd' as LDAP credentials;
# - GitLab queries the LDAP server with 'jane.doe' and 'p#ssw0rd'.
#
# If you are using "uid: 'userPrincipalName'" on ActiveDirectory you need to
# disable this setting, because the userPrincipalName contains an '#'.
allow_username_or_email_login: true
# Base where we can search for users
#
# Ex. ou=People,dc=gitlab,dc=example
#
base: 'OU=Washington\, D.C.,OU=United States,OU=NA,DC=my,DC=domain,DC=net'
# Filter LDAP users
#
# Format: RFC 4515 http://tools.ietf.org/search/rfc4515
# Ex. (employeeType=developer)
#
# Note: GitLab does not support omniauth-ldap's custom filter syntax.
#
#user_filter: ''
EOS
This was, of course, a whitespace issue. See lines below:
gitlab_rails['ldap_enabled'] = true
gitlab_rails['ldap_servers'] = YAML.load <<-EOS # remember to close this block with 'EOS' below
main: # 'main' is the GitLab 'provider ID' of this LDAP server
## label
#
# A human-friendly name for your LDAP server. It is OK to change the label later,
# for instance if you find out it is too large to fit on the web page.
#
# Example: 'Paris' or 'Acme, Ltd.'
label: 'LDAP'

Resources