roadmap
roadmap copied to clipboard
Error while integrate with Keycloak OpenID Connect
Hi, currently I am trying to integrate Keycloak as the OAuth provider and serve the basic authenticating functionality for my organization. I am following the guide from the wiki (https://github.com/DMPRoadmap/roadmap/wiki/Installation) and I am able to run the application in Apache web server. However, when I tried to integrate Keycloak (the OAuth provider used by my organisation) into the DMPRoadmap following the guide (https://github.com/DMPRoadmap/roadmap/wiki/OAuth-Providers), I met some error.
Please complete the following fields as applicable:
What version of the DMPRoadmap code are you running? (e.g. v2.2.0) v4.0.2
Expected behaviour: After authenticated with Keycloak, the authenticated user should be added to the users table in the roadmap database and authenticated to DMPRoadmap.
Actual behaviour: After authenticated with Keycloak, the application return a code 500 Internal Error with the error message: `ActionView::Template::Error ('nil' is not an ActiveModel-compatible object. It must implement :to_partial_path.): 13: <%= f.email_field(:email, class: "form-control", "aria-required": true) %> 14: 15:
app/views/shared/_create_account_form.html.erb:16 app/views/shared/_create_account_form.html.erb:1 app/views/devise/registrations/new.html.erb:62 `
Steps to reproduce: After following the guide in wiki to complete the installation and pushed to web server, I followed the guide from omniauth-keycloak (https://github.com/ccrockett/omniauth-keycloak) exactly and replaced the information as needed (e.g. keycloak client id, client secret, realm and etc.).
Your help is much appreciated.
Hi @yeehengteh it sounds like the org_partial
mentioned in the error is not getting all of the information it needs. The particular one is expecting an array of Org objects.
Do you have any orgs defined in your orgs table? I would suggest placing some debug statements prior to that render command to see what information its trying to send to the partial
Hi, thank you for your reply. Actually I have made some progress, but I am curious on the password in user model. Since most of the SSO provider did not return password in the hash after authentication, if I would like to restrict users to sign in with SSO only, the password in users table will prevent the users creation on first login due to password cannot be null. Do you have any suggestion I can bypass the password in the account creation?
Glad to hear you were able to make progress @yeehengteh.
SSO providers should never send a user's password back to the application. The gem we use to manage the application's security, Devise, does however require that a password be present in order for you to create the user record.
My fork has a different sign in/up workflow, but you can reference it for examples of how to handle this for your implementation. Here is the link to how I generate the random password. I do this only in the SSO scenario. Users are still able to sign up with a regular email+password.
I also make sure that we do not display this random password field when they've come through the SSO workflow, I just place the password on the page in a hidden field. You can see an example of that here
Thank you very much for the solution. I am currently testing the solution on my development server. However, there is one concern I would like to ask. In this case, when the user first sign in with SSO, the user will be redirected to sign up page. With hidden_field
in HTML, the user should still be able to notice the random password if they debug the HTML page. So, does it mean the user can sign in locally if they use the random password?
yes, that is a possibility. They can also use the 'forgot password' link to change that random password if they choose to (although they would still need to have access to the associated email address).
Regardless of how they log in though, SSO or random password, they are logged into the same account.
If it is a concern for you, you can try adding the logic that generates the random password to the create action on the registrations_controller.rb
instead. That way it would not appear in a hidden field on the page.
I see. I will test it out in my development environment. Thank you very much for the explanation and guidance.
Hi @briri , thank you for your suggestion. I am able to run DMP Roadmap in my server. However, I would like to ask for your suggestion once again on the organization selection when first time login registration. I would like to fill the text field with the organization attribute from the hash return by Keycloak and make the field as hidden_field
and register the account. But, when I code to do so in HTML, the backend seems like comparing the orgs_id
instead of the name. May I know is there another way round to make it works?
Hi @yeehengteh the processing of the Org record can be found in the OrgSelectable concern and the HashToOrg service.
You will need to change your hidden field so that the attributes are id="org_name" name="org[name]"
. This will let the code lookup the Org record in the database by its name instead of the id.
If you are sending users to a federation webpage that allows them to select an Org for SSO, then you may want to allow the system to create new Org records. To do that, you will need to set the 'restrict_orgs' flag to false in your application config. Note though, that enabling this will allow users to create orgs when signing up, adding contributors to their DMP, or when editing their profile. This can create duplicate records and invalid orgs though when users have typos or enter in test data.
Hi @briri thank you for your suggestion and sorry for the late reply. I am able to modify this application to my organisation needs. However, I have more questions to ask. Previously, I was insert the KeyCloak oidc provider into the identifier_schemes
table directly with mysql command. The reason is that because I do not understand the context
in the table. I guessed the bit field number to be: 1 = for_authenticaiton and 4 = for_users, so the context turn out to be 14?
No, those bit flags are more complicated. In this case you'd want to use 9. Here is how it works:
# 01 - for_authentication
# 02 - for_orgs
# 03 - for_authentication + for_orgs
# 04 - for_plans
# 05 - for_authentication + for_plans
# 06 - for_orgs + for_plans
# 07 - for_authentication + for_plans + for_orgs
# 08 - for_users
# 09 - for_authentication + for_users
# 10 - for_orgs + for_users
# 11 - for_authentication + for_orgs + for_users
# 12 - for_plans + for_users
# 13 - for_authentication + for_plans + for_users
# 14 - for_orgs + for_plans + for_users
# 15 - for_authentication + for_orgs + for_plans + for_users
... etc.