Azure AD Enterprise App SAML configuration - azure-active-directory

I am trying to configure a SAML non-gallery Enterprise app and am having a problem with configuring the claims. To summarize the current claims, objectGUID is being sent as the name identifier. They send extensionAttribute6 as OrgID. GivenName, sn and e-mail address are sent without any changes.
AD Connect has been configured to sync objectGUID and extensionAttribute6 to AAD, and those attributes are available in the SSO configuration blade for the Enterprise App.
My questions are:
1) Does a Namespace need to be defined for the objectGUID, or can it just be selected from the source attribute in the claim and name identifier?
2) How to transform the extensionAttribute6 to be OrgID?
The current claim rules in ADFS are:
1)
c:[Type ==
"http://schemas.microsoft.com/ws/2008/06/identity/claims/windowsaccountname",
Issuer == "AD AUTHORITY"]
=> issue(store = "Active Directory", types = ("GUID"), query = ";objectGuid;{0}", param = c.Value);
2)
c:[Type == "GUID"]
=> issue(Type = "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/nameidentifier",
Issuer = c.Issuer, OriginalIssuer = c.OriginalIssuer, Value = c.Value,
ValueType = c.ValueType,
Properties["http://schemas.xmlsoap.org/ws/2005/05/identity/claimproperties/format"]
= "urn:oasis:names:tc:SAML:1.1:nameid-format:unspecified");
3)
c:[Type ==
"http://schemas.microsoft.com/ws/2008/06/identity/claims/windowsaccountname",
Issuer == "AD AUTHORITY"]
=> issue(store = "Active Directory", types = ("givenName", "sn", "OrgID", "mail"), query =
";givenName,sn,extensionAttribute6,mail;{0}", param = c.Value);

You do not have to specify the namespace when you are mapping the User.ObjectID as the NameID claim. Also note that do not select any NameID Format and keep that as Default. Azure AD does support the pairwise Name Identifier. That means if the Service Provider is sending the NameID Format then the app will get that from Azure AD based on the Format specified in the SAML Request.
If you are trying to map the User.ObjectID claim as another claim then you can add the Namespace value as needed but it based on how the app need that back.
About transforming OrgID I Am not sure what you want to send. You can define that as a claim name and then select the ExtensionAttribute 6 as value and if the value exist for the user then you should see that in the SAML Response.
I hope this helps.
Thanks and Regards,
Jeevan Desarda

Related

Airflow Configuring AD/LDAP Admin Users And Regular Users

I have Airflow successfully setup to work with my AD/LDAP when everyone is a superuser and data profiler. But now I want to define an admin group and a regular user group. I have the following settings,
Working Config Where Everyone Is An Admin:
# set a connection without encryption: uri = ldap://<your.ldap.server>:<port>
uri = ldap://123.456.789:123
user_filter = objectClass=*
# in case of Active Directory you would use: user_name_attr = sAMAccountName
user_name_attr = sAMAccountName
# group_member_attr should be set accordingly with *_filter
# eg :
# group_member_attr = groupMembership
# superuser_filter = groupMembership=CN=airflow-super-users...
group_member_attr = member
group_name_attr = CN
group_filter = objectclass=group
bind_user = CN=blah,OU=foo,DC=us,DC=bar,DC=com
bind_password = yahoo
basedn = DC=us,DC=bar,DC=com
# Set search_scope to one of them: BASE, LEVEL , SUBTREE
# Set search_scope to SUBTREE if using Active Directory, and not specifying an Organizational Unit
search_scope = SUBTREE
New Config With Specific Admin Group Set:
# set a connection without encryption: uri = ldap://<your.ldap.server>:<port>
uri = ldap://123.456.789:123
user_filter = objectclass=*
# in case of Active Directory you would use: user_name_attr = sAMAccountName
user_name_attr = sAMAccountName
# group_member_attr should be set accordingly with *_filter
# eg :
# group_member_attr = groupMembership
# superuser_filter = groupMembership=CN=airflow-super-users...
superuser_filter = memberOf=CN=MyAdminGroupName,OU=foo,DC=us,DC=bar,DC=com
data_profiler_filter = memberOf=CN=MyAdminGroupName,OU=foo,DC=us,DC=bar,DC=com
group_member_attr = member
group_name_attr = CN
group_filter = objectclass=group
bind_user = CN=blah,OU=foo,DC=us,DC=bar,DC=com
bind_password = yahoo
basedn = DC=us,DC=bar,DC=com
# Set search_scope to one of them: BASE, LEVEL , SUBTREE
# Set search_scope to SUBTREE if using Active Directory, and not specifying an Organizational Unit
search_scope = SUBTREE
Resource: https://airflow.apache.org/security.html
With this new configuration I am able to log into the Airflow UI but I'm no longer able to view the Admin tab. I am 100% sure I am a part of the admin group MyAdminGroupName. I'm also not sure where to put my regular user group name MyRegularGroupName.
Can someone please guide me on how to configure my Admin group (MyAdminGroupName) and my regular user group (MyRegularGroupName)?
I also struggled with setting up LDAP in Airflow.
First of: What is group_filter = objectclass=group in your config? I cannot find it specified in the docs or in the ldap_auth.py.
Then, your group_member_attr is set to member, but in the filter queries you're using memberOf, so I guess that memberOf should be your group_member_attr (it usually is, if your using Active Directory).
Your superuser_filter and data_profiler_filter look good to me.
To whoever reads this: the filters are inserted into a string like this in the code: (&(<FILTER_HERE>)), so if you want to build a more sophisticated filter, take this into account.
E.g. I wanted to only give three users superuser rights (using environment variables for config):
AIRFLOW__LDAP__SUPERUSER_FILTER: "&(objectCategory=Person)(|(sAMAccountName=user1)(sAMAccountName=user2)(sAMAccountName=user3))(memberOf=CN=MyDepartment,OU=Departments,OU=UserGroup,DC=MyCompany,DC=local)"
Regarding your question about MyRegularUserGroup: I guess, you can specify the user filter to filter for persons in your regular user group and then specify the admin group for superuser and data profiler. But that would only work if the admin group is a subset of the regular user group.
Hope that helps.

ADFS 3, Create a Rule to Send Group Membership as a Claim

I am trying to send a few groups memberships as a claim on ADFS3 to a cloud relying party.
I am using a Microsoft article (Below) to Create a Rule to Send Group Membership as a Claim. the MS article says under Claim rule template, select Send Group Membership as Claim and then after giving a name to the rule and selecting a group from the Active Directory, it does not specify what to choose for "Outgoing Claim type" and what to enter in "Outgoing Claim Value" box.
Does anyone have any suggestions?
https://learn.microsoft.com/en-us/windows-server/identity/ad-fs/operations/create-a-rule-to-send-group-membership-as-a-claim
Thanks,
Majid
The following custom rules worked.
#RuleName = "Add Group Claims"
c:[Type == "http://schemas.microsoft.com/ws/2008/06/identity/claims/windowsaccountname",
Issuer == "AD AUTHORITY"]
=> add(store = "Active Directory", types = ("http://test.com/phase1"), query =
";memberOf;{0}", param = c.Value);
#RuleName = "Edit Group"
c:[Type == "http://test.com/phase1"]
=> add(Type = "http://test.com/phase2", Value = RegExReplace(c.Value, ",[^\n]*", ""));
#RuleName = "Remove CN from Group"
c:[Type == "http://test.com/phase2"]
=> add(Type = "http://schemas.xmlsoap.org/claims/Group", Value = RegExReplace(c.Value,
"^CN=", ""));
#RuleName = "Send Only Groups Containing ADFS"
c:[Type == "http://schemas.xmlsoap.org/claims/Group", Value =~ "(?i)Groups-prefix"]
Assume you wanted to pass AD group "isAdmin".
The first part is selecting that group in AD.
Then decide on a group name (e.g. http://company.com/Admin) and then a group value (e.g. isAdmin).
Then if the user is a member of that group, you will get a claim:
http://company.com/Admin/isAdmin

Gerrit authentication against ActiveDirectory

I am trying to get Gerrit to authenticate against anActiveDirectory LDAP server, but I'm having trouble finding the right combination of LDAP settings to make it work. I'm seeing errors like this in the error_log:
WARN com.google.gerrit.server.auth.ldap.LdapRealm : Cannot discover type of LDAP server at ldap://ldapserver.company.com:3268, assuming the server is RFC 2307 compliant.
javax.naming.NamingException: [LDAP: error code 1 - 000004DC: LdapErr: DSID-0C090748, comment: In order to perform this operation a successful bind must be completed on the connection., data 0, v2580^#]; remaining name ''
Is there a "typical" ActiveDirectory config for Gerrit, and should I be using LDAP_BINDauthentication?
LDAP (as opposed to LDAP_BIND) is the correct authentication type.
This was almost completely answered here:
[ldap]
server = ldap://dc.ad.company.com:3268
username = ldapuser#ad.company.com
accountBase = DC=ad,DC=company,DC=com
groupBase = DC=ad,DC=company,DC=com
accountPattern = (&(objectClass=person)(sAMAccountName=${username}))
accountFullName = displayName
accountEmailAddress = mail
accountSshUserName = sAMAccountName
groupMemberPattern = (sAMAccountName=${username})
groupName = cn
localUsernameToLowerCase = true
However, in my case, there is no ad component to the LDAP server hostname, so it looks more like:
[ldap]
server = ldap://something.company.com:3268
username = ldapuser#company.com
accountBase = DC=company,DC=com
groupBase = DC=company,DC=com
accountPattern = (&(objectClass=person)(sAMAccountName=${username}))
accountFullName = displayName
accountEmailAddress = mail
accountSshUserName = sAMAccountName
groupMemberPattern = (sAMAccountName=${username})
groupName = cn
localUsernameToLowerCase = true
Also, you need to add the LDAP password to etc/secure.config (or you can use SecureStore), which should only be readable by the Gerrit user:
[ldap]
password = yourpassword
You will see a error like this if this is not done:
ERROR com.google.gerrit.server.auth.ldap.LdapRealm : Cannot query LDAP to autenticate user
javax.naming.NamingException: [LDAP: error code 1 - 000004DC: LdapErr: DSID-0C090748, comment: In order to perform this operation a successful bind must be completed on the connection., data 0, v2580^#]; remaining name 'DC=company,DC=com'
After this, you can log in with the AD username (without any #company.com parts, just the username) and your usual password.

Different Permissions in Apache Shiro for every User?

I built a database with the entity user and permission
user (id, email, password, permission)
permission (id, create_user, delete_user, user_fk)
create_user and delete_user is BOOLEAN.
Relationship: One-One
Now every user can have it's own permissions.
My question is: How can I use shiro to read the permissions from the database?
If you really only wish to assign permissions on user level, you can "fake" the roles table to make Shiro happy.
As Wouter mentioned, use the JdbcRealm and specify the 3 queries for your table setup.
You should modify your permission table to have this structure:
permission (id, permissionname, user_fk)
Then you insert rows for the create_user/delete_user rights as needed.
This way it's very simple to add another permission (reset_password for example) to your setup, without the need to modify the db schema.
In the shiro.ini (or how you call the your shiro config file):
jdbcRealm = org.apache.shiro.realm.jdbc.JdbcRealm
For the queries use then this:
jdbcRealm.authenticationQuery = select password from user where email=?
jdbcRealm.userRolesQuery = select id from user where email=?
jdbcRealm.authenticationQuery = select permissionname from permission where user_fk=?
The small trick in your setup is: you don't have roles at all, so we just return the id of the user as the role name.
When the lookup in the permission table is done, it then uses the role name (=user pk) and returns the associated permissions.
You should configure a JdbcReam in your .ini file:
jdbcRealm=org.apache.shiro.realm.jdbc.JdbcRealm
If you change your schema to adhere to the shiro queries, no extra config is needed. You need tables users, user_roles and roles_permissions.
See the source code how the exact column names should be:
https://svn.apache.org/repos/asf/shiro/trunk/core/src/main/java/org/apache/shiro/realm/jdbc/JdbcRealm.java
Alternatively you can configure your own queries to match your schema in the .ini file like so:
jdbcRealm.authenticationQuery=<your password select statement>
jdbcRealm.userRolesQuery=<your role names for username select statement>
jdbcRealm.authenticationQuery=<your permissions for role name select statement>

Schema Changes to Integrate Facebook and Google Login

I have Users table to store user details with password and the authentication for the Application is working good with this.
But we want to integrate Facebook and Google Login in our system so please advise the related schema modifications.
CREATE TABLE dbo.Users(
UserId int IDENTITY(1, 1) PRIMARY KEY,
UserTypeId int, -- Admin = 1, End User = 2. (We have a master table for this, but eliminating here for simplicity)
UserName nvarchar(16) NOT NULL UNIQUE,
UserPassword nvarchar(16),
FirstName nvarchar(64),
LastName nvarchar(64),
DateOfBirth date,
Gender char(1),
PhoneNumber nvarchar(16),
Email nvarchar(128) UNIQUE,
IsActive bit,
UpdateTime datetime default CURRENT_TIMESTAMP )
Here is what I am thinking:
1) Once the user authenticated from Facebook or Google then the application will have claims (emailId)
2) The application should validate the emailId existence in Users Table and if exists it will allow login.
Q1> So will this require any update for the existing Row in Users Table?
Q2> If the user record does not exists (based on emailId claim record) then I think we should add the new record in users table?
Q3> In case of Add: What will be the Username and Password values?
Q4> Can the user (the added record) do a normal login without Facebook login?
Thanks.
In order to accept OpenID logins, you will have to accept and store the users' OpenID-URLs. This URL identifies the user just like an email address does.
Q1: Depends: If you want to allow both OpenID-logins and normal login for the same user, you will have to add another column to the table. If you don't allow mixed logins, you could use your Email column to store the OpenID URL.
Q2: Yes, if you see a new OpenID-URL, handle it just like an unknown email address
Q3: You will have to ask the user to pick a username - I assume you do the same for your current users. If you want to allow both logins for the same user, you will have to ask the user to set a password - otherwise they can only login through their OpenID provider.
Q4: Only if you did ask for a username and a password (see Q3)
Please note that allowing the same user to login through OpenID and using conventional username/password introduces potential security problem: A user might not unserstand that you're asking them to set a password and enter their Facebook (or Google) password. Or they might just not care and use the same password everywhere. If they do so and your database does not encrypt the password properly, your database will store the Facebook names and unencrypted passwords... even if just 10% used the same password on your site - just imagine what they could do with that.

Resources