mirror of
https://github.com/LaCasemate/fab-manager.git
synced 2024-11-29 10:24:20 +01:00
[SSO] updated user's documentation
This commit is contained in:
parent
336158c5ad
commit
627073f2be
14
README.md
14
README.md
@ -29,8 +29,9 @@ FabManager is the FabLab management solution. It is web-based, open-source and t
|
||||
7.2.2. [Applying changes](#i18n-apply)
|
||||
8. [Open Projects](#open-projects)
|
||||
9. [Plugins](#plugins)
|
||||
10. [Known issues](#known-issues)
|
||||
11. [Related Documentation](#related-documentation)
|
||||
10. [Single Sign-On](#sso)
|
||||
11. [Known issues](#known-issues)
|
||||
12. [Related Documentation](#related-documentation)
|
||||
|
||||
|
||||
|
||||
@ -619,6 +620,15 @@ To install a plugin, you just have to copy the plugin folder which contains its
|
||||
|
||||
You can see an example on the [repo of navinum gamification plugin](https://github.com/LaCasemate/navinum-gamification)
|
||||
|
||||
<a name="sso"></a>
|
||||
## Single Sign-On
|
||||
|
||||
Fab-manager can be connected to a [Single Sign-On](https://en.wikipedia.org/wiki/Single_sign-on) server which will provide its own authentication for the platform's users.
|
||||
Currently OAuth 2 is the only supported protocol for SSO authentication.
|
||||
|
||||
For an example of how to use configure a SSO in Fab-manager, please read [sso_with_github.md](doc/sso_with_github.md).
|
||||
Developers may find informations on how to implement their own authentication protocol in [sso_authentication.md](doc/sso_authentication.md).
|
||||
|
||||
<a name="known-issues"></a>
|
||||
## Known issues
|
||||
|
||||
|
@ -14,7 +14,7 @@ class Users::OmniauthCallbacksController < Devise::OmniauthCallbacksController
|
||||
@user.username = generate_unique_username(@user.username)
|
||||
end
|
||||
# If the email is mapped, we check its uniqueness. If the email is already in use, we mark it as duplicate with an
|
||||
# unique random string because.
|
||||
# unique random string, because:
|
||||
# - if it is the same user, his email will be filled from the SSO when he merge his accounts
|
||||
# - if it is not the same user, this will prevent the raise of PG::UniqueViolation
|
||||
if active_provider.sso_fields.include?('user.email') and email_exists?(@user.email)
|
||||
@ -22,7 +22,7 @@ class Users::OmniauthCallbacksController < Devise::OmniauthCallbacksController
|
||||
@user.email = "<#{old_mail}>#{Devise.friendly_token}-duplicate"
|
||||
flash[:alert] = t('omniauth.email_already_linked_to_another_account_please_input_your_authentication_code', OLD_MAIL: old_mail)
|
||||
end
|
||||
else
|
||||
else # => update of an existing user
|
||||
if username_exists?(@user.username, @user.id)
|
||||
flash[:alert] = t('omniauth.your_username_is_already_linked_to_another_account_unable_to_update_it', USERNAME: @user.username)
|
||||
@user.username = User.find(@user.id).username
|
||||
|
@ -1,95 +1,105 @@
|
||||
# How to add an authentication method to the FabLab ?
|
||||
# How to add an authentication method to the Fab-Manager ?
|
||||
|
||||
First, take a look at the [OmniAuth list of strategies](https://github.com/intridea/omniauth/wiki/List-of-Strategies)
|
||||
for the Strategy or Developer Strategy you want to add to the FabLab.
|
||||
First, take a look at the [OmniAuth list of strategies](https://github.com/intridea/omniauth/wiki/List-of-Strategies) for the Strategy or Developer Strategy you want to add to the Fab-Manager.
|
||||
|
||||
For this guide, we will consider you want to add a generic *developer strategy*, like LDAP.
|
||||
|
||||
Create the OmniAuth implementation ( **lib/omni_auth/strategies/ldap_provider.rb** )
|
||||
|
||||
# first require the OmniAuth gem you added to your Gemfile (see the link above for a list of gems)
|
||||
require 'omniauth-ldap'
|
||||
module OmniAuth
|
||||
module Strategies
|
||||
# in the class name, replace Ldap with the kind of authentication you are implementing
|
||||
class SsoLdapProvider < OmniAuth::Strategies::LDAP
|
||||
# implement the logic here, see the gem specific documentation for more details
|
||||
end
|
||||
end
|
||||
```ruby
|
||||
# first require the OmniAuth gem you added to your Gemfile (see the link above for a list of gems)
|
||||
require 'omniauth-ldap'
|
||||
module OmniAuth
|
||||
module Strategies
|
||||
# in the class name, replace Ldap with the kind of authentication you are implementing
|
||||
class SsoLdapProvider < OmniAuth::Strategies::LDAP
|
||||
# implement the logic here, see the gem specific documentation for more details
|
||||
end
|
||||
end
|
||||
end
|
||||
```
|
||||
|
||||
Create the ActiveRecord models ( **from the terminal** )
|
||||
|
||||
# in the models names, replace Ldap with the kind of authentication you are implementing
|
||||
# replace ldap_fields with the fields you need for implementing LDAP or whatever you are implementing
|
||||
$ rails g model LdapProvider ...ldap_fields
|
||||
$ rails g model LdapMapping ldap_provider:belongs_to local_field:string local_model:string ...ldap_fields
|
||||
```bash
|
||||
# in the models names, replace Ldap with the kind of authentication you are implementing
|
||||
# replace ldap_fields with the fields you need for implementing LDAP or whatever you are implementing
|
||||
rails g model LdapProvider ...ldap_fields
|
||||
rails g model LdapMapping ldap_provider:belongs_to local_field:string local_model:string ...ldap_fields
|
||||
```
|
||||
|
||||
Complete the Provider Model ( **app/model/ldap_provider.rb** )
|
||||
|
||||
class LdapProvider < ActiveRecord::Base
|
||||
has_one :auth_provider, as: :providable
|
||||
has_many :ldap_mappings, dependent: :destroy
|
||||
accepts_nested_attributes_for :ldap_mappings, allow_destroy: true
|
||||
|
||||
# return here the fields you want to protect from being directly on the FabLab, typically mapped fields
|
||||
def protected_fields
|
||||
fields = []
|
||||
ldap_mappings.each do |mapping|
|
||||
fields.push(mapping.local_model+'.'+mapping.local_field)
|
||||
end
|
||||
fields
|
||||
end
|
||||
|
||||
# return here the link the current users will have to follow to edit his profile on the SSO
|
||||
def profile_url
|
||||
# you can also create a profile_url field in the Database model
|
||||
end
|
||||
```ruby
|
||||
class LdapProvider < ActiveRecord::Base
|
||||
has_one :auth_provider, as: :providable
|
||||
has_many :ldap_mappings, dependent: :destroy
|
||||
accepts_nested_attributes_for :ldap_mappings, allow_destroy: true
|
||||
|
||||
# return here the fields you want to protect from being directly on the Fab-Manager, typically mapped fields
|
||||
def protected_fields
|
||||
fields = []
|
||||
ldap_mappings.each do |mapping|
|
||||
fields.push(mapping.local_model+'.'+mapping.local_field)
|
||||
end
|
||||
|
||||
fields
|
||||
end
|
||||
|
||||
# return here the link the current users will have to follow to edit his profile on the SSO
|
||||
def profile_url
|
||||
# you can also create a profile_url field in the Database model
|
||||
end
|
||||
end
|
||||
```
|
||||
Whitelist your implementation fields in the controller ( **app/controllers/api/auth_providers_controller.rb** )
|
||||
|
||||
class API::AuthProvidersController < API::ApiController
|
||||
...
|
||||
private
|
||||
def provider_params
|
||||
if params['auth_provider']['providable_type'] == DatabaseProvider.name
|
||||
...
|
||||
elsif if params['auth_provider']['providable_type'] == LdapProvider.name
|
||||
params.require(:auth_provider).permit(:name, :providable_type, providable_attributes: [
|
||||
# list here your LdapProvider model's fields, followed by the mappings :
|
||||
ldap_mappings_attributes: [
|
||||
:id, :local_model, :local_field, ...
|
||||
# add your other customs LdapMapping fields, don't forget the :_destroy symbol if
|
||||
# you want your admin to be able to remove mappings
|
||||
]
|
||||
])
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
List the fields to display in the JSON API view ( **app/views/api/auth_providers/show.json.jbuilder** )
|
||||
|
||||
json.partial! 'api/auth_providers/auth_provider', auth_provider: @provider
|
||||
|
||||
...
|
||||
|
||||
if @provider.providable_type == LdapProvider.name
|
||||
json.providable_attributes do
|
||||
json.extract! @provider.providable, :id, ... # list LdapProvider fields here
|
||||
json.ldap_mappings_attributes @provider.providable.ldap_mappings do |m|
|
||||
json.extract! m, :id, :local_model, :local_field, ... # list LdapMapping fields here
|
||||
end
|
||||
```ruby
|
||||
class API::AuthProvidersController < API::ApiController
|
||||
...
|
||||
private
|
||||
def provider_params
|
||||
if params['auth_provider']['providable_type'] == DatabaseProvider.name
|
||||
...
|
||||
elsif if params['auth_provider']['providable_type'] == LdapProvider.name
|
||||
params.require(:auth_provider).permit(:name, :providable_type, providable_attributes: [
|
||||
# list here your LdapProvider model's fields, followed by the mappings :
|
||||
ldap_mappings_attributes: [
|
||||
:id, :local_model, :local_field, ...
|
||||
# add your other customs LdapMapping fields, don't forget the :_destroy symbol if
|
||||
# you want your admin to be able to remove mappings
|
||||
]
|
||||
])
|
||||
end
|
||||
end
|
||||
end
|
||||
```
|
||||
|
||||
List the fields to display in the JSON API view ( **app/views/api/auth_providers/show.json.jbuilder** )
|
||||
|
||||
```ruby
|
||||
json.partial! 'api/auth_providers/auth_provider', auth_provider: @provider
|
||||
|
||||
...
|
||||
|
||||
if @provider.providable_type == LdapProvider.name
|
||||
json.providable_attributes do
|
||||
json.extract! @provider.providable, :id, ... # list LdapProvider fields here
|
||||
json.ldap_mappings_attributes @provider.providable.ldap_mappings do |m|
|
||||
json.extract! m, :id, :local_model, :local_field, ... # list LdapMapping fields here
|
||||
end
|
||||
end
|
||||
end
|
||||
```
|
||||
|
||||
Configure the initializer ( **config/initializers/devise.rb** )
|
||||
|
||||
require_relative '../../lib/omni_auth/omni_auth'
|
||||
...
|
||||
elsif active_provider.providable_type == LdapProvider.name
|
||||
config.omniauth OmniAuth::Strategies::SsoLdapProvider.name.to_sym, # pass here the required parameters, see the gem documentation for details
|
||||
end
|
||||
```ruby
|
||||
require_relative '../../lib/omni_auth/omni_auth'
|
||||
...
|
||||
elsif active_provider.providable_type == LdapProvider.name
|
||||
config.omniauth OmniAuth::Strategies::SsoLdapProvider.name.to_sym, # pass here the required parameters, see the gem documentation for details
|
||||
end
|
||||
```
|
||||
|
||||
Finally you have to create an admin interface with AngularJS:
|
||||
|
||||
@ -97,34 +107,37 @@ Finally you have to create an admin interface with AngularJS:
|
||||
- **app/assets/templates/admin/authentifications/_ldap_mapping.html.erb** must contains html partial to configure the LdapMappings, see _oauth2_mapping.html.erb for a working example
|
||||
- **app/assets/javascript/controllers/admin/authentifications.coffee**
|
||||
|
||||
```coffeescript
|
||||
## list of supported authentication methods
|
||||
METHODS = {
|
||||
...
|
||||
'LdapProvider' : 'LDAP' # add the name of your ActiveRecord model class here as a hash key, associated with a human readable name as a hash value (string)
|
||||
}
|
||||
|
||||
## list of supported authentication methods
|
||||
METHODS = {
|
||||
...
|
||||
'LdapProvider' : 'LDAP' # add the name of your ActiveRecord model class here as a hash key, associated with a human readable name as a hash value (string)
|
||||
}
|
||||
Application.Controllers.controller "newAuthentificationController", ...
|
||||
|
||||
$scope.updateProvidable = ->
|
||||
...
|
||||
if $scope.provider.providable_type == 'LdapProvider'
|
||||
# you may want to do some stuff to initialize your provider here
|
||||
|
||||
Application.Controllers.controller "newAuthentificationController", ...
|
||||
|
||||
$scope.updateProvidable = ->
|
||||
...
|
||||
if $scope.provider.providable_type == 'LdapProvider'
|
||||
# you may want to do some stuff to initialize your provider here
|
||||
|
||||
$scope.registerProvider = ->
|
||||
...
|
||||
# === LdapProvider ===
|
||||
else if $scope.provider.providable_type == 'LdapProvider'
|
||||
# here you may want to do some data validation
|
||||
# then: save the settings
|
||||
AuthProvider.save auth_provider: $scope.provider, (provider) ->
|
||||
# register was a success, display a message, redirect, etc.
|
||||
|
||||
$scope.registerProvider = ->
|
||||
...
|
||||
# === LdapProvider ===
|
||||
else if $scope.provider.providable_type == 'LdapProvider'
|
||||
# here you may want to do some data validation
|
||||
# then: save the settings
|
||||
AuthProvider.save auth_provider: $scope.provider, (provider) ->
|
||||
# register was a success, display a message, redirect, etc.
|
||||
```
|
||||
|
||||
And to include this interface into the existing one ( **app/assets/templates/admin/authentifications/edit.html.erb**)
|
||||
|
||||
<form role="form" name="providerForm" class="form-horizontal" novalidate>
|
||||
...
|
||||
<!-- Add the following ng-include inside the providerForm -->
|
||||
<ng-include src="'<%= asset_path 'admin/authentifications/_ldap.html'%>'" ng-if="provider.providable_type == 'LdapProvider'"></ng-include>
|
||||
</form>
|
||||
```html
|
||||
<form role="form" name="providerForm" class="form-horizontal" novalidate>
|
||||
...
|
||||
<!-- Add the following ng-include inside the providerForm -->
|
||||
<ng-include src="'<%= asset_path 'admin/authentifications/_ldap.html'%>'" ng-if="provider.providable_type == 'LdapProvider'"></ng-include>
|
||||
</form>
|
||||
```
|
||||
|
52
doc/sso_with_github.md
Normal file
52
doc/sso_with_github.md
Normal file
@ -0,0 +1,52 @@
|
||||
# How to configure Fab-manager to use a Single Sign-On authentication?
|
||||
|
||||
For this guide, we will use [GitHub](https://developer.github.com/v3/oauth/) as an authentication provider, because it has a standard implementation of the protocol and it is free to use.
|
||||
|
||||
- First, you must have a GitHub account. This is free, so create one if you don't have any.
|
||||
Visit https://github.com/join?source=login to create an account.
|
||||
|
||||
- Secondly, you will need to register your fab-manager instance as an application in GitHub.
|
||||
Visit https://github.com/settings/applications/new to register your instance.
|
||||
- In `Homepage URL`, put the public URL where your fab-manager's instance is located (eg. https://example.com).
|
||||
- In `Authorization callback URL`, you must specify an URL that will match this scheme: https://example.com/users/auth/oauth2-github/callback (replace my-fablab.example.com with your own fab-manager's address).
|
||||
|
||||
- You'll be redirected to a page displaying to important informations: your **Client ID** and your **Client Secret**.
|
||||
|
||||
- Now go to your fab-manager's instance, login as an administrator, go to `Users management` and `Authentication`.
|
||||
Click `Add a new authentication provider`, and select _OAuth 2.0_ in the `Authentication type` drop-down list.
|
||||
As a name, you can set whatever you want but, you must be aware that:
|
||||
1. You will need to type this name in a terminal to activate the provider, so prefer avoiding chars that must be escaped.
|
||||
2. This name will be occasionally displayed to end users, so prefer sweet names.
|
||||
|
||||
- Fulfill the form with the following parameters:
|
||||
- **Common URL**: `https://github.com/login/oauth` This is the common part in the URL of the two following parameters.
|
||||
- **Authorization endpoint**: `/authorize` This URL can be found [here](https://developer.github.com/v3/oauth/).
|
||||
- **Token Acquisition Endpoint**: `/access_token` This URL can be found [here](https://developer.github.com/v3/oauth/).
|
||||
- **Profile edition URL**: `https://github.com/settings/profile` This is the URL where you are directed when you click on `Edit profile` in your GitHub dashboard.
|
||||
- **Client identifier**: Your Client ID, collected just before.
|
||||
- **Client secret**: Your Client Secret, collected just before.
|
||||
|
||||
- Then you will need to define the matching of the fields between the data used in fab-manager and the data that the external SSO can provide.
|
||||
Note that the only mandatory field is User.uid.
|
||||
To continue with our GitHub example, you will need to look at [this documentation page](https://developer.github.com/v3/users/#get-the-authenticated-user) to know witch field can be mapped and how and [this one](https://developer.github.com/v3/) to know the root URL of the API.
|
||||
- **Model**: `User`
|
||||
- **Field**: `uid`
|
||||
- **API endpoint URL**: `https://api.github.com/user` Here you can set a complete URL **OR** only an endpoint referring to the previously set **Common URL**.
|
||||
- **API type**: `JSON` Only JSON API are currently supported
|
||||
- **API fields**: `id` According to the GitHub API documentation, this is the name of the JSON field which uniquely identify the user.
|
||||
You are free to map more fields, like `Profile.github` to `html_url`, or `Profile.avatar` to `avatar_url`...
|
||||
|
||||
- Once you are done, your newly created authentication provider, will be marked as **Pending** in the authentication providers list.
|
||||
To set it as the current active provider, you must open a terminal on the hosting server (and/or container) and run the following commands:
|
||||
|
||||
```bash
|
||||
# replace GitHub with the name of the provider you just created
|
||||
rake fablab:switch_auth_provider[GitHub]
|
||||
```
|
||||
|
||||
- As the command just prompted you, you have to re-compile the assets (with eg, `rake tmp:clear` - this vary with the method you used to deploy your instance)
|
||||
- Then restart the web-server or the container.
|
||||
- Finally, to notify all existing users about the changement and send them their migration code/link, run:
|
||||
```bash
|
||||
rake fablab:notify_auth_changed
|
||||
```
|
Loading…
Reference in New Issue
Block a user