Problems with Login over EntraID regarding rights

Hello! So, we have the following issue. We have configured SSO with entra ID and everything is working as expected (so far). For now it was tested only with users with administration rights (to all collections). But now we are working on “real” users with limited rights to an collections and i “got stuck”.

To replicate the issue i have done following:

  1. Create an user that has Limited Access to an Collection → OK

  2. Invite the user via Invite-Link → OK

  3. At this Point the user clicks on the invite link (in a Private windows just to be sure), does his authentication, comes back to specify, is logged in and has access to the stuff that he needs to see. → OK

It looks like this:

Now comes “the bug” Part: User closes Browser. User Open a Browser (again in a Private window) user opens specify in Browser, clicks on Login with OICD (or whatever that button is named), makes authentication in EntraID, will be redirected back to specify after succesfull auth and does NOT see what he should see. I Would expect the same specify as first time. Instead he gets a json output with an error. This looks like this:

So, my first idea is that some rights are screwed or something so i doublecked everything but looks fine. So i set a password to this user to be able to login localy instead with External Identity Provider. So again, loged in “localy” and Bam, everything is working like it should.

If i give the User rights to the collection 4 (see second screenshot) then its working also with OIDC, BUT, he should not be able to do stuff in Collection “4”. He has no rights for it. So i “assume” he goes for collection 4 because its the first collection in database or something like this? All other collections have higher IDs.

So, i think i found a bug or is there any setting regarding this behavior?

Hi @dfernandez,
Just to confirm,
Could you check if there are any duplicate user entries in the “spuserexternalid” database table?
See this post for more info: SSO Authentication Issue with Duplicate User Entries in spuserexternalid Table - Get Help - Specify Community Forum

Yes, there are none, this happens if the user clicks more than once on the invitation link, i allready know this behavior, but is not the case here. There is only one with the right specifyuser_id and it matches with the id in the table specifyuser.

I just wondering where the collectionid = 4 is coming in my case.

1 Like

This is the same bug we had! Even collectionid 4 is the same! Thought it was such a weird fluke that I decided to close it, but I was also able to replicate across 2 users.

1 Like

I wonder if it is these lines that are causing it. @dfernandez, in your situation, does the user only have access to one other collection?

Hello @markp !

Yes! We have 4-5 Collections and the user is only allowed to exactly 1 Collection. We don’t use divisions at all. But its same behavior you described in the github issue.

Blockquote
I wonder if it is these lines that are causing it.

available_collections[0].id

Maybe system should check the first avaiable collection for the given user? Im really not a programmer but my first avaiable collection IS 4 just not for the given user :slight_smile:

Thank you for this, this provides evidence that it is not related to Cannot set batch of agents for collection access · Issue #2405 · specify/specify7 · GitHub. Based on the only agents we had encountered the error with being in the one isolated division, I thought this was related, but it appears not to be.

I guess this brings about two questions:

  1. What is it about the users that it is occurring with that are different than others? We have had other users that only have access to one collection be able to login through SSO just fine, so I don’t think it is the indexing ([0]) or the condition being the issue then.
  2. I’ll have to ask our two users who have experienced the error, but presumably if I were to revoke their read-only access to collectionid 4, they would be able to login? Maybe I’ll work with them today to see about that

I would also ask: Why its working the first time sending an invititation link perfectly but not a second time when user does actually a login with sso. And why it is working perfectly when same userrecord is logged in with a local password. Specify has all needed information but it looks like in “SSO Login” case is not “initialised” right.

Maybe some parameter missing in callbackurl or something? Just a idea.

Another idea: When i log in “localy”, there is a screen where i need to select the collection. This specific screen is not showing up when i do SSO login. On this screen i need to select my collection “accounts/choose_collection/?next=”

This is the notable difference in the 2 ways of login.

So I worked with one of the two users this morning, once given, the read-only access to collectionid 4 can then be revoked, and they are able to login fine through SSO. So as a workaround if this user really needed to get setup, and if its possible in the constraints of your access model, the read-only access could be given and then immediately revoked as soon as they switch back to their normal collection via the collection picking in the nav. They just need to be able to complete that route once. As I just did it this morning, time will tell if any session or cookie expiring messes things up, but I think it should be fine for them from here on out.

Your idea about the parameter seems plausible, I’ll look at the code some more today and see if I can spot anything. After working with the user above, it further supports that this bug will only present itself the second time a user logs in (with the first being the login immediately after setup). After the second time, they will end up going to the one collection they have access to just fine, which is what enables the permission to collectionid 4 to be revoked.

3rd instance of this error today, with one new thing to add.

  1. User had previously signed in many times with SSO successfully (a few months of usage at this point), so this is not only an issue during initial setup. This means that this bug may present itself even after users have been migrated to SSO.

Specify version: 7.9.6.2

Some further updates on this:

  1. The error is propagating. Currently, I cannot determine a pattern of what is causing certain users to experience the collectionid 4 error while others are not, but we are up to 7.

I mention the below because the affected user was one of those 7, however at this time it is uncertain if connected. There may be three factors in play, (all linked by some common cause?), issue #5323, issue #5326, and the new information from below, not yet a GitHub issue.

  1. For the first time today, a user experienced an unlinking of their specifyuser_id with the spuserexternalid. On the login screen, they received the unknownOicUser message. Their name and details from the {providerName:string} were loaded correctly. The time since they last logged in was one week. This timing could be important because the remedial actions taken for SSO Authentication Issue with Duplicate User Entries in spuserexternalid Table - #3 by markp were performed 7 days ago, but on a different user, so cause and effect there is murky. As other users are able to sign in, it seems unlikely that is the cause at this time.

To complete a login, the user needed to use the local authentication (user/pass), which is a problem, because after transitioning to SSO (in our case, but probably in the case of others) the users will no longer know their password, they will be set to some strong random value. This means for any further users that experience this, they won’t be able to login until I can reset their password for them.

My first step was to look in the database to see if there were any issues with the specifyuser_id field in the spuserexternalid table. There is a record for this user like any other. and it points to the correct specifyuser_id. However, after today, now there are two records for this user in the specifyexternalid table, which will presumably trigger #5362 on their next login.

I have setup a development environment of specify with a freshly created dummy database, building from the source code (currently using the 7.9.6.2 tag). I am going to see if I can replicate any of this in a consistent way through a test keycloak instance. I believe that the only file that needs to be looked at is specify7/specifyweb/accounts/views.py at production · specify/specify7 · GitHub, and will start there.

Okay, I can replicate #5323 (this issue)! I thought it would take a while, but it actually occurred on the second login attempt. Below are some details of the setup

Setup

  • Fresh database created with Specify 6.8.03, schema 2.10
  • Two collections, Test Collection 1, Test Collection 2. Confirmed that Test Collection 1 has id=4
  • Standard development docker compose, 7.9.6.2 tag checked out
  • Keycloak service running in the same docker compose

Users

  • Alice is admin. Should never experience #5323 because they have access to all collections
  • Bob. Only has access to Test Collection 2. Read-only access to everything in collection 2.

Tests

:white_check_mark: indicates that the user can login
:x: indicates that the user experiences the NoMatchingRuleException error.

Test 1: Ensure Alice can log in through SSO

:white_check_mark: Alice can log in as expected via keycloak, and specify asks to associate external provider with local account as expected.

Test 2: Ensure Bob can log in through SSO

:white_check_mark: Bob can log in as expected via keycloak, and specify asks to associate external provider with local account as expected.

Test 3: Bob attempts second login attempt through SSO

:x: Bob doesn’t log out of specify via the logout button. Instead, browser is closed and new private browser window is spawned. Bob attempts to log in through SSO. Recieves the following error

NoMatchingRuleException:
  0:
    collectionid: 4
    userid: 2
    resource: "/system/sp7/collection"
    action: "access"

Docker logs for the specify container read as follows. I have substituted the long random values for parameters to shorten things:

"GET /accounts/login/?next=/specify/ HTTP/1.0" 200 771
"POST /accounts/login/?next=/specify/ HTTP/1.0" 302 0
"GET /accounts/oic_callback/?state={value}&session_state={value}&iss={value} HTTP/1.0" 302 0
"GET /specify HTTP/1.0" 301 0
[WARNING] [django.request:224] Forbidden: /specify/
"GET /specify/ HTTP/1.0" 403 121
"GET /favicon.ico HTTP/1.0" 302 0

On the keycloak side, I see 2 sessions open for bob, and one for alice

User Type Started Last Access IP address Clients
bob REGULAR 1/30/2025 1:20:42 PM 1/30/2025 1:20:42 PM 172.18.01 specify
alice REGULAR 1/30/2025 1:14:22 PM 1/30/2025 1:18:13 PM 172.18.01 specify
bob REGULAR 1/30/2025 1:19:28 PM 1/30/2025 1:19:28 PM 172.18.01 specify

Test 4: Redo test 3 (test reproducibility)

:x: New private window, same result.

Test 5: See if bob logging out of Specify through logout button changes things

:white_check_mark: Bob opens up a fresh private window. Instead of using keycloak, bob logs in through local auth. Bob presses “Log out”. Bob closes window. Bob opens up fresh private window, signs in through keycloak, no error.

Test 6: Bob doesn’t log out through Specify (confirm reproducibility)

:x: Bob experiences error again

Solution

I think I found the problem? The collection cookie is not being set in these lines of code. Since this is using django’s auth, I believe that is the reason why the local logout had the effect it did.

If I implement a crude fix, by manually setting the collection cookie to what I know bob needs, bob is able to login just fine.

login(request, cast(AbstractBaseUser, spuserexternalid.specifyuser), backend='django.contrib.auth.backends.ModelBackend')
response = http.HttpResponseRedirect('/specify')
response = set_cookie('collection', '32768', max_age=3600)
return response
3 Likes

Nice Ressearch on this topic @markp !
I can follow your testing and i agree. Will be there a real fix in a next release?

@dfernandez I’ve created a PR with a fix that I believe should do the trick, however not sure if it is being targeted for the next release or not.