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!
Related
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
I'm trying to allow domain users to log into my rundeck instance by following the guide https://vinusumi.wordpress.com/2017/12/28/setup-active-directory-authentication-for-rundeck/. However, I'm running into 2 issues.
For some reason, I'm unable to log into rundeck with a user thats added to the "rundeck_admins" group. I confirmed that the credentials are correct and I believe that the info I added to the "jaas-activedirectory.conf" is syntactically correct and accurate based on my AD settings. According to the "/var/log/rundeck/service.log" it says the following:
2018-12-13 20:13:29.689 DEBUG --- [tp1465511423-25] ailsUsernamePasswordAuthenticationFilter : Updated SecurityContextHolder to contain null Authentication
2018-12-13 20:13:29.689 DEBUG --- [tp1465511423-25] ailsUsernamePasswordAuthenticationFilter : Delegating to
authentication failure handler grails.plugin.springsecurity.web.authentication.AjaxAwareAuthenticationFailureHandler#51aaa9d4
I'm having trouble figuring out the proper syntax regarding the yaml file used for my "rundeck_users" group
description: "Ops Engineers can launch jobs but not edit them"
context:
project: *
for:
resource:
- equals:
kind: 'node'
allow: [read,update,refresh]
- equals:
kind: 'job'
allow: [read,run,kill]
- equals:
kind: 'adhoc'
allow: [read,run,kill]
- equals:
kind: 'event'
allow: [read,create]
job:
- match:
name: '.*'
allow: [read,run,kill]
adhoc:
- match:
name: '.*'
allow: [read,run,kill]
node:
- match:
nodename: '.*'
allow: [read,run,refresh]
by:
group:
- rundeck_users
---
context:
application: rundeck
description: "Ops Engineers can launch jobs but not edit them"
for:
project:
- match:
name: '*'
allow: [read]
system:
- match:
name: '.*'
allow: [read]
by:
group:
- rundeck_users
1.- Make sure the authentication is being read. When rundeck is starting
<..>
2018-12-14 01:52:57.186 INFO --- [ main] rundeckapp.BootStrap : RSS feeds disabled
2018-12-14 01:52:57.187 INFO --- [ main] rundeckapp.BootStrap : Using jaas authentication <<<<<<<<<
<..>
2.- Verify the yaml content is correct for example using http://www.yamllint.com/
3.- Use an existing/working aclpolicy and use your group for testing purpose and check if the acl policy is causing the issue.
Hope it helps
AD authentication - These steps are relevant for rundeck version 3 and up on centos7.
For older rundeck version see procedure I posted here:
https://groups.google.com/forum/#!msg/rundeck-discuss/P2qQHNpDct4/aP0ot7V2BAAJ
Create AD config file with the following content:
AD {
com.dtolabs.rundeck.jetty.jaas.JettyCachingLdapLoginModule required
debug="true"
contextFactory="com.sun.jndi.ldap.LdapCtxFactory"
providerUrl="ldap://<ip>:389 ldap://<ip>:389"
bindDn="CN=authUser,CN=Users,DC=your,DC=domain,DC=com"
bindPassword="<authUserPassword>"
authenticationMethod="simple"
forceBindingLogin="true"
userBaseDn="CN=Users,DC=your,DC=domain,DC=com"
userRdnAttribute="sAMAccountName"
userIdAttribute="sAMAccountName"
userPasswordAttribute="unicodePwd"
userObjectClass="person"
roleBaseDn="CN=Users,DC=your,DC=domain,DC=com"
roleNameAttribute="sAMAccountName"
roleMemberAttribute="member"
roleObjectClass="group"
cacheDurationMillis="300000"
reportStatistics="true";
};
Create file /etc/sysconfig/rundeckd with the following lines.
Note that LOGIN_MODULE value should be the same as what you set in your file.
export JAAS_CONF=/path/to/file/jaas-AD.conf
export LOGIN_MODULE=AD
I recommend creating full control yaml at first so you can test AD authentication, and then remove permissions as necessary. Note groups in yaml should be the same as in your AD.
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
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.
I have a few of their projects on Symfony 2. On one of them today itch to do a total upgrade to the newest versions. Prior to that, everything worked perfectly. And the projects themselves, and sonata admin and authorization.
After the upgrade, I did not knurl old configs, and carefully read the manuals for all the vendors, and prescribed all over again. There were a few problems, but the project has started pretty quickly. The site works, authorization works, not only works admin panel. Today, a day fumbling, and can not understand why I have the admin screen blank.
in /src/Itfrogs/SiteBundle/Resources/config/services.yml
...
sonata.admin.dictionary.group:
class: Itfrogs\SiteBundle\Admin\Model\DictionaryGroupsAdmin
tags:
- { name: sonata.admin, manager_type: orm, group: Content, label: Dictionary Group }
arguments:
- ~
- Itfrogs\SiteBundle\Entity\DictionaryGroup
- ~
calls:
- [ setTranslationDomain, [ItfrogsSiteBundle]]
...
in main config.yml
...
sonata_block:
default_contexts: [cms]
blocks:
sonata.admin.block.admin_list:
contexts: [admin]
#sonata.admin_doctrine_orm.block.audit:
# contexts: [admin]
sonata.block.service.text:
sonata.block.service.action:
sonata.block.service.rss:
sonata.media.block.media:
sonata_admin:
dashboard:
blocks:
-
position: left
type: sonata.admin.block.admin_list
...
I think it's basic. Rest on a manual. The class Itfrogs\SiteBundle\Admin\Model\DictionaryGroupsAdmin and the entity Itfrogs\SiteBundle\Entity\DictionaryGroup remained the same.
Before loading the class does not reach. I checked.
Prompt, where to search?
If any more configs need tell me - I'll post.
Provided you're using the latest Sonata Admin Bundle it should be something like this according to the documentation:
sonata_block:
default_contexts: [cms]
blocks:
sonata.admin.block.admin_list:
contexts: [admin]
If you're using Sonata user bundle with FOSUser bundle then you may not have the right permissions to view your pages.
If you're in fact using FOSUser, Try in command line:
php app/console fos:user:create adminuser --super-admin
You can find more here
**hint: but you must configure the sonata block in your configuration
sonata_block:
default_contexts: [cms]
blocks:
sonata.admin.block.admin_list:
contexts: [admin]