From: D B. <ba...@aw...> - 2020-04-17 16:49:11
|
Hi, from the manual I gather that unity supports quite complex scenarios for combining remote and local authentication - but I wasn't able to piece together from it how to configure what I need. I've got local users with username identities who authenticate with passwords. Now I'd like to add a remote SAML IDP with the following behaviour: 1. If a user tries remote authentication for a locally existing username for the first time, they are asked to associate those identities. This should prevent malicious users from hijacking existing local users' accounts by registering the same username at the remote IDP. 2. If a user tries remote authenticiation after association with a local account, they can just log in normally. 3. If a user tries remote authentication and the username doesn't exist locally, they are shown a pre-filled registration form (with the values obtained from the remote IDP) where they have to accept the terms and conditions. Admins are notified and can accept registrations. After acceptance, the local account is associated with the remote identity. 4. Local login with passwords for existing local users is still possible. Ideally, newly created remote users are able to set a password and thus have a 'local' account as well. I can't quite figure out how to do 1 and 3 yet. Re 1: How can I force association and not just let remote users in as soon as the usernames match? I suspect it has to do with the identity mapping in the input translation profile, described in http://www.unity-idm.eu/documentation/unity-3.2.1/manual.html#input-translation but I'm unclear if CREATE_OR_MATCH, MATCH, REQUIRE_MATCH, or UPDATE_OR_MATCH would be the correct value to chose. And what else is required to make it work. Re 3: In my remote saml authentication facility, I've set the registration form to an existing, public form that collects username and email 'From remote IdP and shown RO'. However, when testing I'm never presented with this registration form after remotely authenticating - seems I'm missing some option? As a side note: it seems account association can produce entities with multiple usernames. Both of those usernames will be sent to my SAML SPs - what's best practice here to avoid weird effects? Can I somehow tell unity to only send along the username that was created first? Or to import a new (remote) username only if the entity doesn't already have one? Cheers, D |
From: Krzysztof B. <kb...@un...> - 2020-04-21 21:12:44
|
Hi D, uff, a complex email :-) Let's start from a small terminology clarification, to ensure we are on the same page. In Unity there a certain situation which is called as "unknown remote user" flow. It is triggered when a user authenticates using external IdP, but after successful remote authentication, this user is not mapped (by means of input translation profile) onto _existing_ local entity. Example: user, after returning from external IdP, was mapped to 'username' identity with value 'awst', but there is no 'awst' present in Unity's DB. And now the remaining clarifications: 1. So in the "unknown remote user" flow you can either (a) put user into registration flow (which typically includes an interactive step of filling some form, but need not to) or (b) put user into account association flow where user has to link the unknown remote identity with some other existing locally account. So (b) is essentially when remote identity is auxiliary, an addition to a regular, mandatory local account. A rare case. Finally there is (c) - user can choose on her own whether to do (a) or (b). In practice (a) or (c) is used. 2. In order to trigger the "unknown remote user" flow, make sure _not to auto create_ a user using input profile. I.e. if you use in your profile mapIdentity action with CREATE_OR_MATCH, this flow will be never triggered, as profile will either match with the existing user or create a local account for the remote one and match to it. I guess this is your problem from "as a side note". 3. Unity has no feature to decide whether to start flow (a) or (b) or go to (c) at runtime. Which path is taken is a result of static configuration. I agree that we may have a feature here: we can allow admins to specify some rule to check whether there is a local user who looks _similar_ to the remote one, and basing on this similarity either suggest user identity linking, or skip it. However this is a very complex feature: similarity will be different between deployments, checking it may require full text searches with text distance metering support etc. Some will check by same email, some with name, some with pair of surname and first name, some will take into account institution etc. And even with all of this - what if the similarity check returns that there is no one similar, but user has a local account and wants to link with it? 4. Your particular case sounds for me as one example of the above: on one hand you want to ask user to link accounts if remote username matches local one. But on another you don't trust remote one. So can you guarantee that remote user "johnny" is not the same as previously registered local "j.smith"? I.e. there is not only a security precaution not to link automatically to take into account, but also a question why not to allow for linking when usernames do _not_ match. OK, so what you can do with Unity is: ignore whether remote username is the same as the local one, just treat remote username as remote 'identifier' typed identity, perhaps with some prefix as a namespace. Function of this identifier will be to match _returning_ remote users. Follow path (c), i.e. when unknown remote user flow is triggered (i.e. this will be when a given user logs into unity with remote identity for the very 1st time): allow the user to select whether to link account or register. If linking is chosen Unity will ask the user for authenticating with the local account (2nd authN for the user), after it accounts will be linked, login with either of them will be equivalent (well, subject to MFA settings, but typically). If user chooses to register then you can provide a registration form exactly as you envision: prefilled with remote data and also prompting for password setup. Does it work for you? Also note that there are also other options, much different. E.g. you can create a registration form, using remote credential. So you can guide users to register using remote identity. This is more typical path, as you can instruct user more clearly what happens, is more often used then the "unknown remote user flow", in which users have to try to authenticate even when they don't have any account/haven't access your service yet. This may be puzzling for some, who will search for "sign up" instead of trying to "sign in". Other option is to remove account linking from the flow, if this is a rare choice, and rather treat it as special case: two accounts can be also associated outside of login flow. I hope I clarified this at least a little bit, not other way round :-) Best, Krzysztof |
From: D B. <ba...@aw...> - 2020-04-22 15:36:01
|
Hi! First of all: thanks for taking the time to answer these detailed questions, I really appreciate it! On 21/04/2020 23:12, Krzysztof Benedyczak wrote: > 1. So in the "unknown remote user" flow you can either (a) put user > into registration flow (which typically includes an interactive step > of filling some form, but need not to) or (b) put user into account > association flow where user has to link the unknown remote identity > with some other existing locally account. So (b) is essentially when > remote identity is auxiliary, an addition to a regular, mandatory > local account. A rare case. Finally there is (c) - user can choose on > her own whether to do (a) or (b). In practice (a) or (c) is used. It sounds like (c) would be the most useful in my case, so let's go with that. > 2. In order to trigger the "unknown remote user" flow, make sure _not > to auto create_ a user using input profile. I.e. if you use in your > profile mapIdentity action with CREATE_OR_MATCH, this flow will be > never triggered, as profile will either match with the existing user > or create a local account for the remote one and match to it. I guess > this is your problem from "as a side note". OK, so now I've got this in my input translation profile: mapIdentity unityIdentityType: identifier expression: 'remote-' + attr['username'] credential requirement: Password requirement effect: UPDATE_OR_MATCH In my remote SAML facility config, I've selected the external registration form I've created and disabled account association. The registration form collects identities 'identifier' 'From remote IdP and shown RO' and 'userName' from user input (so hopefully a user can chose a local username on registration). I still never get to see the registration dialog. In the logs, unity complains: unity.server.externaltranslation.InputTranslationEngineImpl: Identity MappedIdentity [mode=UPDATE_OR_MATCH, identity=[identifier] remote-dbaum, credentialRequirement=Password requirement] not found in DB, details of exception follows pl.edu.icm.unity.exceptions.UnknownIdentityException: Entity [identifier] remote-dbaum is unknown On the GUI, unity complains: The remote authentication was successful, however your identity is not accepted by the local service. Please contact administrators or try to register first. Pretty much the same thing happens for mode=MATCH. What do I need to do to put users into the remote registration flow? I'm guessing my input translation profile isn't doing the right thing? > 3. Unity has no feature to decide whether to start flow (a) or (b) or > go to (c) at runtime. Which path is taken is a result of static > configuration. I agree that we may have a feature here: we can allow > admins to specify some rule to check whether there is a local user > who looks _similar_ to the remote one, and basing on this similarity > either suggest user identity linking, or skip it. However this is a > very complex feature: similarity will be different between > deployments, checking it may require full text searches with text > distance metering support etc. Some will check by same email, some > with name, some with pair of surname and first name, some will take > into account institution etc. And even with all of this - what if the > similarity check returns that there is no one similar, but user has a > local account and wants to link with it? > > 4. Your particular case sounds for me as one example of the above: > on one hand you want to ask user to link accounts if remote username > matches local one. But on another you don't trust remote one. So can > you guarantee that remote user "johnny" is not the same as > previously registered local "j.smith"? I.e. there is not only a > security precaution not to link automatically to take into account, > but also a question why not to allow for linking when usernames do > _not_ match. Nah, I agree, it doesn't need to be that complicated in unity. 1) I don't mind if they have different remote and local usernames - as long as the local username is always the one propagated to unity's clients. 2) Users who want their pre-existing local and remote accounts linked can be expected to manually trigger the association process. Users who don't have a pre-existing local account should be presented with a registration form. Also, automatically guessing which remote user corresponds to a local user sounds like a security nightmare. > OK, so what you can do with Unity is: ignore whether remote username > is the same as the local one, just treat remote username as remote > 'identifier' typed identity, perhaps with some prefix as a > namespace. Function of this identifier will be to match _returning_ > remote users. Follow path (c), i.e. when unknown remote user flow is > triggered (i.e. this will be when a given user logs into unity with > remote identity for the very 1st time): allow the user to select > whether to link account or register. Cool! But... how do I do that? I've tried using a remote identifier identity but can't get to the registration form or to the account association (see above). > If linking is chosen Unity will > ask the user for authenticating with the local account (2nd authN for > the user), after it accounts will be linked, login with either of > them will be equivalent (well, subject to MFA settings, but > typically). If user chooses to register then you can provide a > registration form exactly as you envision: prefilled with remote data > and also prompting for password setup. > > Does it work for you? That would work for me, but currently it doesn't yet work in my setup ;-) > Also note that there are also other options, > much different. E.g. you can create a registration form, using > remote credential. So you can guide users to register using remote > identity. This is more typical path, as you can instruct user more > clearly what happens, is more often used then the "unknown remote > user flow", in which users have to try to authenticate even when they > don't have any account/haven't access your service yet. This may be > puzzling for some, who will search for "sign up" instead of trying to > "sign in". So the difference is what? You get all remote users to register and afterwards they can manually associate their remote and local accounts? Cheers, D |
From: Krzysztof B. <kb...@un...> - 2020-04-22 16:38:44
|
Hi, W dniu 22.04.2020 o 17:35, D Baum pisze: > 2. In order to trigger the "unknown remote user" flow, make sure _not >> to auto create_ a user using input profile. I.e. if you use in your >> profile mapIdentity action with CREATE_OR_MATCH, this flow will be >> never triggered, as profile will either match with the existing user >> or create a local account for the remote one and match to it. I guess >> this is your problem from "as a side note". > OK, so now I've got this in my input translation profile: > mapIdentity > unityIdentityType: identifier > expression: 'remote-' + attr['username'] > credential requirement: Password requirement > effect: UPDATE_OR_MATCH > > In my remote SAML facility config, I've selected the external > registration form I've created and disabled account association. The > registration form collects identities 'identifier' 'From remote IdP and > shown RO' and 'userName' from user input (so hopefully a user can chose > a local username on registration). > > I still never get to see the registration dialog. In the logs, unity > complains: > unity.server.externaltranslation.InputTranslationEngineImpl: Identity > MappedIdentity [mode=UPDATE_OR_MATCH, identity=[identifier] > remote-dbaum, credentialRequirement=Password requirement] not found in > DB, details of exception follows > pl.edu.icm.unity.exceptions.UnknownIdentityException: Entity > [identifier] remote-dbaum is unknown > > On the GUI, unity complains: > The remote authentication was successful, however your identity is not > accepted by the local service. Please contact administrators or try to > register first. > > Pretty much the same thing happens for mode=MATCH. > > What do I need to do to put users into the remote registration flow? I'm > guessing my input translation profile isn't doing the right thing? Hah, I forgot about case (d): you can also fail authentication in case of unknown remote user :-) You haven't shared a more complete log so can't say for sure, but seems that your profile is fine: it maps remote user "dbaum" onto local identifier with value "remote-dbaum". This identity is not in DB so unknown remote user flow should be triggered (if I could see a log around the end of profile execution and just after it, I were sure). So two things to ensure, both in your remote authenticator config: 1. that you have enabled account association. For OAuth it is a setting of an authnticator. For SAML you can have default setting, and also overwrite it per each trusted IDP. For LDAP there is one setting (see Interactive Login settings). 2. that you have configured which registration form should be presented to unknown remote users. For SAML authenticators as above: you can set one for authenticator, and also overwrite it per IdP. For OAuth authenticators it is set per provider (the first option in Advanced section). For LDAP sits next to linking. HTH, if not please provide debug log from input profile an on. > >> Also note that there are also other options, >> much different. E.g. you can create a registration form, using >> remote credential. So you can guide users to register using remote >> identity. This is more typical path, as you can instruct user more >> clearly what happens, is more often used then the "unknown remote >> user flow", in which users have to try to authenticate even when they >> don't have any account/haven't access your service yet. This may be >> puzzling for some, who will search for "sign up" instead of trying to >> "sign in". > So the difference is what? You get all remote users to register and > afterwards they can manually associate their remote and local accounts? Yes. If 90% of users registers, then showing some "link account" option will only puzzle them. And those 10% can be instructed that they can go to account association endpoint to perform linking (can be also done from home UI). Cheers, Krzysztof |