##// END OF EJS Templates
auth: updated saml docs, and re-order info on plugin details for easier setup
super-admin -
r5505:3fc95e3b default
parent child Browse files
Show More
@@ -0,0 +1,159 b''
1 .. _config-saml-azure-ref:
2
3
4 SAML 2.0 with Azure Entra ID
5 ----------------------------
6
7 **This plugin is available only in EE Edition.**
8
9 |RCE| supports SAML 2.0 Authentication with Azure Entra ID provider. This allows
10 users to log-in to RhodeCode via SSO mechanism of external identity provider
11 such as Azure AD. The login can be triggered either by the external IDP, or internally
12 by clicking specific authentication button on the log-in page.
13
14
15 Configuration steps
16 ^^^^^^^^^^^^^^^^^^^
17
18 To configure Duo Security SAML authentication, use the following steps:
19
20 1. From the |RCE| interface, select
21 :menuselection:`Admin --> Authentication`
22 2. Activate the `Azure Entra ID` plugin and select :guilabel:`Save`
23 3. Go to newly available menu option called `Azure Entra ID` on the left side.
24 4. Check the `enabled` check box in the plugin configuration section,
25 and fill in the required SAML information and :guilabel:`Save`, for more details,
26 see :ref:`config-saml-azure`
27
28
29 .. _config-saml-azure:
30
31
32 Example SAML Azure Entra ID configuration
33 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
34
35 Example configuration for SAML 2.0 with Azure Entra ID provider
36
37
38 Enabled
39 `True`:
40
41 .. note::
42 Enable or disable this authentication plugin.
43
44
45 Auth Cache TTL
46 `30`:
47
48 .. note::
49 Amount of seconds to cache the authentication and permissions check response call for this plugin.
50 Useful for expensive calls like LDAP to improve the performance of the system (0 means disabled).
51
52 Debug
53 `True`:
54
55 .. note::
56 Enable or disable debug mode that shows SAML errors in the RhodeCode logs.
57
58
59 Auth button name
60 `Azure Entra ID`:
61
62 .. note::
63 Alternative authentication display name. E.g AzureAuth, CorporateID etc.
64
65
66 Entity ID
67 `https://sts.windows.net/APP_ID/`:
68
69 .. note::
70 Identity Provider entity/metadata URI. Known as "Microsoft Entra Identifier"
71 E.g. https://sts.windows.net/abcd-c655-dcee-aab7-abcd/
72
73 SSO URL
74 `https://login.microsoftonline.com/APP_ID/saml2`:
75
76 .. note::
77 SSO (SingleSignOn) endpoint URL of the IdP. This can be used to initialize login, Known also as Login URL
78 E.g. https://login.microsoftonline.com/abcd-c655-dcee-aab7-abcd/saml2
79
80 SLO URL
81 `https://login.microsoftonline.com/APP_ID/saml2`:
82
83 .. note::
84 SLO (SingleLogout) endpoint URL of the IdP. , Known also as Logout URL
85 E.g. https://login.microsoftonline.com/abcd-c655-dcee-aab7-abcd/saml2
86
87 x509cert
88 `<CERTIFICATE_STRING>`:
89
90 .. note::
91 Identity provider public x509 certificate. It will be converted to single-line format without headers.
92 Download the raw base64 encoded certificate from the Identity provider and paste it here.
93
94 SAML Signature
95 `sha-256`:
96
97 .. note::
98 Type of Algorithm to use for verification of SAML signature on Identity provider side.
99
100 SAML Digest
101 `sha-256`:
102
103 .. note::
104 Type of Algorithm to use for verification of SAML digest on Identity provider side.
105
106 Service Provider Cert Dir
107 `/etc/rhodecode/conf/saml_ssl/`:
108
109 .. note::
110 Optional directory to store service provider certificate and private keys.
111 Expected certs for the SP should be stored in this folder as:
112 * sp.key Private Key
113 * sp.crt Public cert
114 * sp_new.crt Future Public cert
115
116 Also you can use other cert to sign the metadata of the SP using the:
117 * metadata.key
118 * metadata.crt
119
120 Expected NameID Format
121 `nameid-format:emailAddress`:
122
123 .. note::
124 The format that specifies how the NameID is sent to the service provider.
125
126 User ID Attribute
127 `user.email`:
128
129 .. note::
130 User ID Attribute name. This defines which attribute in SAML response will be used to link accounts via unique id.
131 Ensure this is returned from DuoSecurity for example via duo_username.
132
133 Username Attribute
134 `user.username`:
135
136 .. note::
137 Username Attribute name. This defines which attribute in SAML response will map to a username.
138
139 Email Attribute
140 `user.email`:
141
142 .. note::
143 Email Attribute name. This defines which attribute in SAML response will map to an email address.
144
145
146
147 Below is example setup from Azure Administration page that can be used with above config.
148
149 .. image:: ../images/saml-azure-service-provider-example.png
150 :alt: Azure SAML setup example
151 :scale: 50 %
152
153
154 Below is an example attribute mapping set for IDP provider required by the above config.
155
156
157 .. image:: ../images/saml-azure-attributes-example.png
158 :alt: Azure SAML setup example
159 :scale: 50 % No newline at end of file
@@ -1,24 +1,39 b''
1 FROM python:3.12.0-bullseye
1 FROM python:3.12.0-bullseye
2
2
3 WORKDIR /project
3 WORKDIR /project
4
4
5 RUN apt-get update \
5 RUN apt-get update \
6 && apt-get install --no-install-recommends --yes \
6 && apt-get install --no-install-recommends --yes \
7 curl \
7 curl \
8 zip \
8 zip \
9 graphviz \
9 graphviz \
10 dvipng \
10 imagemagick \
11 imagemagick \
11 make \
12 make \
13 latexmk \
14 texlive-latex-recommended \
15 texlive-latex-extra \
16 texlive-xetex \
17 fonts-freefont-otf \
18 texlive-fonts-recommended \
19 texlive-lang-greek \
20 tex-gyre \
12 && apt-get autoremove \
21 && apt-get autoremove \
13 && apt-get clean \
22 && apt-get clean \
14 && rm -rf /var/lib/apt/lists/*
23 && rm -rf /var/lib/apt/lists/*
15
24
25 RUN curl "https://awscli.amazonaws.com/awscli-exe-linux-x86_64.zip" -o "awscliv2.zip" && \
26 unzip awscliv2.zip && \
27 ./aws/install && \
28 rm -rf ./aws && \
29 rm awscliv2.zip
30
16 RUN \
31 RUN \
17 python3 -m pip install --no-cache-dir --upgrade pip && \
32 python3 -m pip install --no-cache-dir --upgrade pip && \
18 python3 -m pip install --no-cache-dir Sphinx Pillow
33 python3 -m pip install --no-cache-dir Sphinx Pillow
19
34
20 ADD requirements_docs.txt /project
35 ADD requirements_docs.txt /project
21 RUN \
36 RUN \
22 python3 -m pip install -r requirements_docs.txt
37 python3 -m pip install -r requirements_docs.txt
23
38
24 CMD ["sphinx-build", "-M", "html", ".", "_build"]
39 CMD ["sphinx-build", "-M", "html", ".", "_build"]
@@ -1,88 +1,90 b''
1 .. _auth-saml-bulk-enroll-users-ref:
1 .. _auth-saml-bulk-enroll-users-ref:
2
2
3
3
4 Bulk enroll multiple existing users
4 Bulk enroll multiple existing users
5 -----------------------------------
5 -----------------------------------
6
6
7
7
8 RhodeCode Supports standard SAML 2.0 SSO for the web-application part.
8 RhodeCode Supports standard SAML 2.0 SSO for the web-application part.
9 Below is an example how to enroll list of all or some users to use SAML authentication.
9 Below is an example how to enroll list of all or some users to use SAML authentication.
10 This method simply enables SAML authentication for many users at once.
10 This method simply enables SAML authentication for many users at once.
11
11
12
12
13 From the server RhodeCode Enterprise is running run ishell on the instance which we
13 From the server RhodeCode Enterprise is running run ishell on the instance which we
14 want to apply the SAML migration::
14 want to apply the SAML migration::
15
15
16 rccontrol ishell enterprise-1
16 ./rcstack cli ishell
17
17
18 Follow these steps to enable SAML authentication for multiple users.
18 Follow these steps to enable SAML authentication for multiple users.
19
19
20
20
21 1) Create a user_id => attribute mapping
21 1) Create a user_id => attribute mapping
22
22
23
23
24 `saml2user` is a mapping of external ID from SAML provider such as OneLogin, DuoSecurity, Google.
24 `saml2user` is a mapping of external ID from SAML provider such as OneLogin, DuoSecurity, Google.
25 This mapping consists of local rhodecode user_id mapped to set of required attributes needed to bind SAML
25 This mapping consists of local rhodecode user_id mapped to set of required attributes needed to bind SAML
26 account to internal rhodecode user.
26 account to internal rhodecode user.
27 For example, 123 is local rhodecode user_id, and '48253211' is OneLogin ID.
27 For example, 123 is local rhodecode user_id, and '48253211' is OneLogin ID.
28 For other providers you'd have to figure out what would be the user-id, sometimes it's the email, i.e for Google
28 For other providers you'd have to figure out what would be the user-id, sometimes it's the email, i.e for Google
29 The most important this id needs to be unique for each user.
29 The most important this id needs to be unique for each user.
30
30
31 .. code-block:: python
31 .. code-block:: python
32
32
33 In [1]: saml2user = {
33 In [1]: saml2user = {
34 ...: # OneLogin, uses externalID available to read from in the UI
34 ...: # OneLogin, uses externalID available to read from in the UI
35 ...: 123: {'id': '48253211'},
35 ...: 123: {'id': '48253211'},
36 ...: # for Google/DuoSecurity email is also an option for unique ID
36 ...: # for Google/DuoSecurity email is also an option for unique ID
37 ...: 124: {'id': 'email@domain.com'},
37 ...: 124: {'id': 'email@domain.com'},
38 ...: }
38 ...: }
39
39
40
40
41 2) Import the plugin you want to run migration for.
41 2) Import the plugin you want to run migration for.
42
42
43 From available options pick only one and run the `import` statement
43 From available options pick only one and run the `import` statement
44
44
45 .. code-block:: python
45 .. code-block:: python
46
46
47 # for Duo Security
47 # for Duo Security
48 In [2]: from rc_auth_plugins.auth_duo_security import RhodeCodeAuthPlugin
48 In [2]: from rc_auth_plugins.auth_duo_security import RhodeCodeAuthPlugin
49 # for Azure Entra
50 In [2]: from rc_auth_plugins.auth_azure import RhodeCodeAuthPlugin
49 # for OneLogin
51 # for OneLogin
50 In [2]: from rc_auth_plugins.auth_onelogin import RhodeCodeAuthPlugin
52 In [2]: from rc_auth_plugins.auth_onelogin import RhodeCodeAuthPlugin
51 # generic SAML plugin
53 # generic SAML plugin
52 In [2]: from rc_auth_plugins.auth_saml import RhodeCodeAuthPlugin
54 In [2]: from rc_auth_plugins.auth_saml import RhodeCodeAuthPlugin
53
55
54 3) Run the migration based on saml2user mapping.
56 3) Run the migration based on saml2user mapping.
55
57
56 Enter in the ishell prompt
58 Enter in the ishell prompt
57
59
58 .. code-block:: python
60 .. code-block:: python
59
61
60 In [3]: for user in User.get_all():
62 In [3]: for user in User.get_all():
61 ...: existing_identity = ExternalIdentity().query().filter(ExternalIdentity.local_user_id == user.user_id).scalar()
63 ...: existing_identity = ExternalIdentity().query().filter(ExternalIdentity.local_user_id == user.user_id).scalar()
62 ...: attrs = saml2user.get(user.user_id)
64 ...: attrs = saml2user.get(user.user_id)
63 ...: provider = RhodeCodeAuthPlugin.uid
65 ...: provider = RhodeCodeAuthPlugin.uid
64 ...: if existing_identity:
66 ...: if existing_identity:
65 ...: print('Identity for user `{}` already exists, skipping'.format(user.username))
67 ...: print(f'Identity for user `{user.username}` already exists, skipping')
66 ...: continue
68 ...: continue
67 ...: if attrs:
69 ...: if attrs:
68 ...: external_id = attrs['id']
70 ...: external_id = attrs['id']
69 ...: new_external_identity = ExternalIdentity()
71 ...: new_external_identity = ExternalIdentity()
70 ...: new_external_identity.external_id = external_id
72 ...: new_external_identity.external_id = external_id
71 ...: new_external_identity.external_username = '{}-saml-{}'.format(user.username, user.user_id)
73 ...: new_external_identity.external_username = f'{user.username}-saml-{user.user_id}'
72 ...: new_external_identity.provider_name = provider
74 ...: new_external_identity.provider_name = provider
73 ...: new_external_identity.local_user_id = user.user_id
75 ...: new_external_identity.local_user_id = user.user_id
74 ...: new_external_identity.access_token = ''
76 ...: new_external_identity.access_token = ''
75 ...: new_external_identity.token_secret = ''
77 ...: new_external_identity.token_secret = ''
76 ...: new_external_identity.alt_token = ''
78 ...: new_external_identity.alt_token = ''
77 ...: Session().add(ex_identity)
79 ...: Session().add(ex_identity)
78 ...: Session().commit()
80 ...: Session().commit()
79 ...: print('Set user `{}` external identity bound to ExternalID:{}'.format(user.username, external_id))
81 ...: print(f'Set user `{user.username}` external identity bound to ExternalID:{external_id}')
80
82
81 .. note::
83 .. note::
82
84
83 saml2user can be really big and hard to maintain in ishell. It's also possible
85 saml2user can be really big and hard to maintain in ishell. It's also possible
84 to load it as a JSON file prepared before and stored on disk. To do so run::
86 to load it as a JSON file prepared before and stored on disk. To do so run::
85
87
86 import json
88 import json
87 saml2user = json.loads(open('/path/to/saml2user.json','rb').read())
89 saml2user = json.loads(open('/path/to/saml2user.json','rb').read())
88
90
@@ -1,105 +1,159 b''
1 .. _config-saml-duosecurity-ref:
1 .. _config-saml-duosecurity-ref:
2
2
3
3
4 SAML 2.0 with Duo Security
4 SAML 2.0 with Duo Security
5 --------------------------
5 --------------------------
6
6
7 **This plugin is available only in EE Edition.**
7 **This plugin is available only in EE Edition.**
8
8
9 |RCE| supports SAML 2.0 Authentication with Duo Security provider. This allows
9 |RCE| supports SAML 2.0 Authentication with Duo Security provider. This allows
10 users to log-in to RhodeCode via SSO mechanism of external identity provider
10 users to log-in to RhodeCode via SSO mechanism of external identity provider
11 such as Duo. The login can be triggered either by the external IDP, or internally
11 such as Duo. The login can be triggered either by the external IDP, or internally
12 by clicking specific authentication button on the log-in page.
12 by clicking specific authentication button on the log-in page.
13
13
14
14
15 Configuration steps
15 Configuration steps
16 ^^^^^^^^^^^^^^^^^^^
16 ^^^^^^^^^^^^^^^^^^^
17
17
18 To configure Duo Security SAML authentication, use the following steps:
18 To configure Duo Security SAML authentication, use the following steps:
19
19
20 1. From the |RCE| interface, select
20 1. From the |RCE| interface, select
21 :menuselection:`Admin --> Authentication`
21 :menuselection:`Admin --> Authentication`
22 2. Activate the `Duo Security` plugin and select :guilabel:`Save`
22 2. Activate the `Duo Security` plugin and select :guilabel:`Save`
23 3. Go to newly available menu option called `Duo Security` on the left side.
23 3. Go to newly available menu option called `Duo Security` on the left side.
24 4. Check the `enabled` check box in the plugin configuration section,
24 4. Check the `enabled` check box in the plugin configuration section,
25 and fill in the required SAML information and :guilabel:`Save`, for more details,
25 and fill in the required SAML information and :guilabel:`Save`, for more details,
26 see :ref:`config-saml-duosecurity`
26 see :ref:`config-saml-duosecurity`
27
27
28
28
29 .. _config-saml-duosecurity:
29 .. _config-saml-duosecurity:
30
30
31
31
32 Example SAML Duo Security configuration
32 Example SAML Duo Security configuration
33 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
33 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
34
34
35 Example configuration for SAML 2.0 with Duo Security provider::
35 Example configuration for SAML 2.0 with Duo Security provider
36
37
38 Enabled
39 `True`:
36
40
37 *option*: `enabled` => `True`
41 .. note::
38 # Enable or disable this authentication plugin.
42 Enable or disable this authentication plugin.
43
44
45 Auth Cache TTL
46 `30`:
39
47
40 *option*: `cache_ttl` => `0`
48 .. note::
41 # Amount of seconds to cache the authentication and permissions check response call for this plugin.
49 Amount of seconds to cache the authentication and permissions check response call for this plugin.
42 # Useful for expensive calls like LDAP to improve the performance of the system (0 means disabled).
50 Useful for expensive calls like LDAP to improve the performance of the system (0 means disabled).
51
52 Debug
53 `True`:
43
54
44 *option*: `debug` => `True`
55 .. note::
45 # Enable or disable debug mode that shows SAML errors in the RhodeCode logs.
56 Enable or disable debug mode that shows SAML errors in the RhodeCode logs.
57
58
59 Auth button name
60 `Azure Entra ID`:
46
61
47 *option*: `entity_id` => `http://rc-app.com/dag/saml2/idp/metadata.php`
62 .. note::
48 # Identity Provider entity/metadata URI.
63 Alternative authentication display name. E.g AzureAuth, CorporateID etc.
49 # E.g. https://duo-gateway.com/dag/saml2/idp/metadata.php
64
65
66 Entity ID
67 `https://my-duo-gateway.com/dag/saml2/idp/metadata.php`:
68
69 .. note::
70 Identity Provider entity/metadata URI.
71 E.g. https://duo-gateway.com/dag/saml2/idp/metadata.php
72
73 SSO URL
74 `https://duo-gateway.com/dag/saml2/idp/SSOService.php?spentityid=<metadata_entity_id>`:
50
75
51 *option*: `sso_service_url` => `http://rc-app.com/dag/saml2/idp/SSOService.php?spentityid=http://rc.local.pl/_admin/auth/duosecurity/saml-metadata`
76 .. note::
52 # SSO (SingleSignOn) endpoint URL of the IdP. This can be used to initialize login
77 SSO (SingleSignOn) endpoint URL of the IdP. This can be used to initialize login, Known also as Login URL
53 # E.g. https://duo-gateway.com/dag/saml2/idp/SSOService.php?spentityid=<metadata_entity_id>
78 E.g. http://rc-app.com/dag/saml2/idp/SSOService.php?spentityid=https://docker-dev/_admin/auth/duosecurity/saml-metadata
79
80 SLO URL
81 `https://duo-gateway.com/dag/saml2/idp/SingleLogoutService.php?ReturnTo=<return_url>`:
54
82
55 *option*: `slo_service_url` => `http://rc-app.com/dag/saml2/idp/SingleLogoutService.php?ReturnTo=http://rc-app.com/dag/module.php/duosecurity/logout.php`
83 .. note::
56 # SLO (SingleLogout) endpoint URL of the IdP.
84 SLO (SingleLogout) endpoint URL of the IdP. , Known also as Logout URL
57 # E.g. https://duo-gateway.com/dag/saml2/idp/SingleLogoutService.php?ReturnTo=http://duo-gateway.com/_admin/saml/sign-out-endpoint
85 E.g. http://rc-app.com/dag/saml2/idp/SingleLogoutService.php?ReturnTo=https://docker-dev/_admin/auth/duosecurity/saml-sign-out-endpoint
58
86
59 *option*: `x509cert` => `<CERTIFICATE_STRING>`
87 x509cert
60 # Identity provider public x509 certificate. It will be converted to single-line format without headers
88 `<CERTIFICATE_STRING>`:
61
89
62 *option*: `name_id_format` => `sha-1`
90 .. note::
63 # The format that specifies how the NameID is sent to the service provider.
91 Identity provider public x509 certificate. It will be converted to single-line format without headers.
92 Download the raw base64 encoded certificate from the Identity provider and paste it here.
93
94 SAML Signature
95 `sha-256`:
96
97 .. note::
98 Type of Algorithm to use for verification of SAML signature on Identity provider side.
99
100 SAML Digest
101 `sha-256`:
64
102
65 *option*: `signature_algo` => `sha-256`
103 .. note::
66 # Type of Algorithm to use for verification of SAML signature on Identity provider side
104 Type of Algorithm to use for verification of SAML digest on Identity provider side.
105
106 Service Provider Cert Dir
107 `/etc/rhodecode/conf/saml_ssl/`:
67
108
68 *option*: `digest_algo` => `sha-256`
109 .. note::
69 # Type of Algorithm to use for verification of SAML digest on Identity provider side
110 Optional directory to store service provider certificate and private keys.
111 Expected certs for the SP should be stored in this folder as:
112 * sp.key Private Key
113 * sp.crt Public cert
114 * sp_new.crt Future Public cert
70
115
71 *option*: `cert_dir` => `/etc/saml/`
116 Also you can use other cert to sign the metadata of the SP using the:
72 # Optional directory to store service provider certificate and private keys.
117 * metadata.key
73 # Expected certs for the SP should be stored in this folder as:
118 * metadata.crt
74 # * sp.key Private Key
119
75 # * sp.crt Public cert
120 Expected NameID Format
76 # * sp_new.crt Future Public cert
121 `nameid-format:emailAddress`:
77 #
122
78 # Also you can use other cert to sign the metadata of the SP using the:
123 .. note::
79 # * metadata.key
124 The format that specifies how the NameID is sent to the service provider.
80 # * metadata.crt
125
126 User ID Attribute
127 `PersonImmutableID`:
81
128
82 *option*: `user_id_attribute` => `PersonImmutableID`
129 .. note::
83 # User ID Attribute name. This defines which attribute in SAML response will be used to link accounts via unique id.
130 User ID Attribute name. This defines which attribute in SAML response will be used to link accounts via unique id.
84 # Ensure this is returned from DuoSecurity for example via duo_username
131 Ensure this is returned from DuoSecurity for example via duo_username.
132
133 Username Attribute
134 `User.username`:
85
135
86 *option*: `username_attribute` => `User.username`
136 .. note::
87 # Username Attribute name. This defines which attribute in SAML response will map to an username.
137 Username Attribute name. This defines which attribute in SAML response will map to a username.
88
138
89 *option*: `email_attribute` => `User.email`
139 Email Attribute
90 # Email Attribute name. This defines which attribute in SAML response will map to an email address.
140 `User.email`:
141
142 .. note::
143 Email Attribute name. This defines which attribute in SAML response will map to an email address.
144
91
145
92
146
93 Below is example setup from DUO Administration page that can be used with above config.
147 Below is example setup from DUO Administration page that can be used with above config.
94
148
95 .. image:: ../images/saml-duosecurity-service-provider-example.png
149 .. image:: ../images/saml-duosecurity-service-provider-example.png
96 :alt: DUO Security SAML setup example
150 :alt: DUO Security SAML setup example
97 :scale: 50 %
151 :scale: 50 %
98
152
99
153
100 Below is an example attribute mapping set for IDP provider required by the above config.
154 Below is an example attribute mapping set for IDP provider required by the above config.
101
155
102
156
103 .. image:: ../images/saml-duosecurity-attributes-example.png
157 .. image:: ../images/saml-duosecurity-attributes-example.png
104 :alt: DUO Security SAML setup example
158 :alt: DUO Security SAML setup example
105 :scale: 50 % No newline at end of file
159 :scale: 50 %
@@ -1,19 +1,20 b''
1 .. _config-saml-generic-ref:
1 .. _config-saml-generic-ref:
2
2
3
3
4 SAML 2.0 Authentication
4 SAML 2.0 Authentication
5 -----------------------
5 -----------------------
6
6
7
7
8 **This plugin is available only in EE Edition.**
8 **This plugin is available only in EE Edition.**
9
9
10 RhodeCode Supports standard SAML 2.0 SSO for the web-application part.
10 RhodeCode Supports standard SAML 2.0 SSO for the web-application part.
11
11
12 Please check for reference two example providers:
12 Please check for reference two example providers:
13
13
14 .. toctree::
14 .. toctree::
15
15
16 auth-saml-duosecurity
16 auth-saml-duosecurity
17 auth-saml-onelogin
17 auth-saml-onelogin
18 auth-saml-azure
18 auth-saml-bulk-enroll-users
19 auth-saml-bulk-enroll-users
19
20
@@ -1,106 +1,159 b''
1 .. _config-saml-onelogin-ref:
1 .. _config-saml-onelogin-ref:
2
2
3
3
4 SAML 2.0 with One Login
4 SAML 2.0 with One Login
5 -----------------------
5 -----------------------
6
6
7 **This plugin is available only in EE Edition.**
7 **This plugin is available only in EE Edition.**
8
8
9 |RCE| supports SAML 2.0 Authentication with OneLogin provider. This allows
9 |RCE| supports SAML 2.0 Authentication with OneLogin provider. This allows
10 users to log-in to RhodeCode via SSO mechanism of external identity provider
10 users to log-in to RhodeCode via SSO mechanism of external identity provider
11 such as OneLogin. The login can be triggered either by the external IDP, or internally
11 such as OneLogin. The login can be triggered either by the external IDP, or internally
12 by clicking specific authentication button on the log-in page.
12 by clicking specific authentication button on the log-in page.
13
13
14
14
15 Configuration steps
15 Configuration steps
16 ^^^^^^^^^^^^^^^^^^^
16 ^^^^^^^^^^^^^^^^^^^
17
17
18 To configure OneLogin SAML authentication, use the following steps:
18 To configure OneLogin SAML authentication, use the following steps:
19
19
20 1. From the |RCE| interface, select
20 1. From the |RCE| interface, select
21 :menuselection:`Admin --> Authentication`
21 :menuselection:`Admin --> Authentication`
22 2. Activate the `OneLogin` plugin and select :guilabel:`Save`
22 2. Activate the `OneLogin` plugin and select :guilabel:`Save`
23 3. Go to newly available menu option called `OneLogin` on the left side.
23 3. Go to newly available menu option called `OneLogin` on the left side.
24 4. Check the `enabled` check box in the plugin configuration section,
24 4. Check the `enabled` check box in the plugin configuration section,
25 and fill in the required SAML information and :guilabel:`Save`, for more details,
25 and fill in the required SAML information and :guilabel:`Save`, for more details,
26 see :ref:`config-saml-onelogin`
26 see :ref:`config-saml-onelogin`
27
27
28
28
29 .. _config-saml-onelogin:
29 .. _config-saml-onelogin:
30
30
31
31
32 Example SAML OneLogin configuration
32 Example SAML OneLogin configuration
33 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
33 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
34
34
35 Example configuration for SAML 2.0 with OneLogin provider::
35 Example configuration for SAML 2.0 with OneLogin provider
36
37
38 Enabled
39 `True`:
36
40
37 *option*: `enabled` => `True`
41 .. note::
38 # Enable or disable this authentication plugin.
42 Enable or disable this authentication plugin.
43
44
45 Auth Cache TTL
46 `30`:
39
47
40 *option*: `cache_ttl` => `0`
48 .. note::
41 # Amount of seconds to cache the authentication and permissions check response call for this plugin.
49 Amount of seconds to cache the authentication and permissions check response call for this plugin.
42 # Useful for expensive calls like LDAP to improve the performance of the system (0 means disabled).
50 Useful for expensive calls like LDAP to improve the performance of the system (0 means disabled).
51
52 Debug
53 `True`:
43
54
44 *option*: `debug` => `True`
55 .. note::
45 # Enable or disable debug mode that shows SAML errors in the RhodeCode logs.
56 Enable or disable debug mode that shows SAML errors in the RhodeCode logs.
57
58
59 Auth button name
60 `Azure Entra ID`:
46
61
47 *option*: `entity_id` => `https://app.onelogin.com/saml/metadata/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx`
62 .. note::
48 # Identity Provider entity/metadata URI.
63 Alternative authentication display name. E.g AzureAuth, CorporateID etc.
49 # E.g. https://app.onelogin.com/saml/metadata/<onelogin_connector_id>
64
65
66 Entity ID
67 `https://app.onelogin.com/saml/metadata/<onelogin_connector_id>`:
68
69 .. note::
70 Identity Provider entity/metadata URI.
71 E.g. https://app.onelogin.com/saml/metadata/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
72
73 SSO URL
74 `https://app.onelogin.com/trust/saml2/http-post/sso/<onelogin_connector_id>`:
50
75
51 *option*: `sso_service_url` => `https://customer-domain.onelogin.com/trust/saml2/http-post/sso/xxxxxx`
76 .. note::
52 # SSO (SingleSignOn) endpoint URL of the IdP. This can be used to initialize login
77 SSO (SingleSignOn) endpoint URL of the IdP. This can be used to initialize login, Known also as Login URL
53 # E.g. https://app.onelogin.com/trust/saml2/http-post/sso/<onelogin_connector_id>
78 E.g. https://app.onelogin.com/trust/saml2/http-post/sso/<onelogin_connector_id>
79
80 SLO URL
81 `https://app.onelogin.com/trust/saml2/http-redirect/slo/<onelogin_connector_id>`:
54
82
55 *option*: `slo_service_url` => `https://customer-domain.onelogin.com/trust/saml2/http-redirect/slo/xxxxxx`
83 .. note::
56 # SLO (SingleLogout) endpoint URL of the IdP.
84 SLO (SingleLogout) endpoint URL of the IdP. , Known also as Logout URL
57 # E.g. https://app.onelogin.com/trust/saml2/http-redirect/slo/<onelogin_connector_id>
85 E.g. https://app.onelogin.com/trust/saml2/http-redirect/slo/<onelogin_connector_id>
58
86
59 *option*: `x509cert` => `<CERTIFICATE_STRING>`
87 x509cert
60 # Identity provider public x509 certificate. It will be converted to single-line format without headers
88 `<CERTIFICATE_STRING>`:
61
89
62 *option*: `name_id_format` => `sha-1`
90 .. note::
63 # The format that specifies how the NameID is sent to the service provider.
91 Identity provider public x509 certificate. It will be converted to single-line format without headers.
92 Download the raw base64 encoded certificate from the Identity provider and paste it here.
93
94 SAML Signature
95 `sha-256`:
96
97 .. note::
98 Type of Algorithm to use for verification of SAML signature on Identity provider side.
99
100 SAML Digest
101 `sha-256`:
64
102
65 *option*: `signature_algo` => `sha-256`
103 .. note::
66 # Type of Algorithm to use for verification of SAML signature on Identity provider side
104 Type of Algorithm to use for verification of SAML digest on Identity provider side.
105
106 Service Provider Cert Dir
107 `/etc/rhodecode/conf/saml_ssl/`:
67
108
68 *option*: `digest_algo` => `sha-256`
109 .. note::
69 # Type of Algorithm to use for verification of SAML digest on Identity provider side
110 Optional directory to store service provider certificate and private keys.
111 Expected certs for the SP should be stored in this folder as:
112 * sp.key Private Key
113 * sp.crt Public cert
114 * sp_new.crt Future Public cert
70
115
71 *option*: `cert_dir` => `/etc/saml/`
116 Also you can use other cert to sign the metadata of the SP using the:
72 # Optional directory to store service provider certificate and private keys.
117 * metadata.key
73 # Expected certs for the SP should be stored in this folder as:
118 * metadata.crt
74 # * sp.key Private Key
119
75 # * sp.crt Public cert
120 Expected NameID Format
76 # * sp_new.crt Future Public cert
121 `nameid-format:emailAddress`:
77 #
122
78 # Also you can use other cert to sign the metadata of the SP using the:
123 .. note::
79 # * metadata.key
124 The format that specifies how the NameID is sent to the service provider.
80 # * metadata.crt
125
126 User ID Attribute
127 `PersonImmutableID`:
81
128
82 *option*: `user_id_attribute` => `PersonImmutableID`
129 .. note::
83 # User ID Attribute name. This defines which attribute in SAML response will be used to link accounts via unique id.
130 User ID Attribute name. This defines which attribute in SAML response will be used to link accounts via unique id.
84 # Ensure this is returned from OneLogin for example via Internal ID
131 Ensure this is returned from DuoSecurity for example via duo_username.
132
133 Username Attribute
134 `User.username`:
85
135
86 *option*: `username_attribute` => `User.username`
136 .. note::
87 # Username Attribute name. This defines which attribute in SAML response will map to an username.
137 Username Attribute name. This defines which attribute in SAML response will map to a username.
88
138
89 *option*: `email_attribute` => `User.email`
139 Email Attribute
90 # Email Attribute name. This defines which attribute in SAML response will map to an email address.
140 `User.email`:
141
142 .. note::
143 Email Attribute name. This defines which attribute in SAML response will map to an email address.
91
144
92
145
93
146
94 Below is example setup that can be used with OneLogin SAML authentication that can be used with above config..
147 Below is example setup that can be used with OneLogin SAML authentication that can be used with above config..
95
148
96 .. image:: ../images/saml-onelogin-config-example.png
149 .. image:: ../images/saml-onelogin-config-example.png
97 :alt: OneLogin SAML setup example
150 :alt: OneLogin SAML setup example
98 :scale: 50 %
151 :scale: 50 %
99
152
100
153
101 Below is an example attribute mapping set for IDP provider required by the above config.
154 Below is an example attribute mapping set for IDP provider required by the above config.
102
155
103
156
104 .. image:: ../images/saml-onelogin-attributes-example.png
157 .. image:: ../images/saml-onelogin-attributes-example.png
105 :alt: OneLogin SAML setup example
158 :alt: OneLogin SAML setup example
106 :scale: 50 % No newline at end of file
159 :scale: 50 %
@@ -1,34 +1,35 b''
1 .. _authentication-ref:
1 .. _authentication-ref:
2
2
3 Authentication Options
3 Authentication Options
4 ======================
4 ======================
5
5
6 |RCE| provides a built in authentication against its own database. This is
6 |RCE| provides a built in authentication against its own database. This is
7 implemented using ``RhodeCode Internal`` plugin. This plugin is enabled by default.
7 implemented using ``RhodeCode Internal`` plugin. This plugin is enabled by default.
8 Additionally, |RCE| provides a Pluggable Authentication System. This gives the
8 Additionally, |RCE| provides a Pluggable Authentication System. This gives the
9 administrator greater control over how users authenticate with the system.
9 administrator greater control over how users authenticate with the system.
10
10
11 .. important::
11 .. important::
12
12
13 You can disable the built in |RCE| authentication plugin
13 You can disable the built in |RCE| authentication plugin
14 ``RhodeCode Internal`` and force all authentication to go
14 ``RhodeCode Internal`` and force all authentication to go
15 through your authentication plugin of choice e.g LDAP only.
15 through your authentication plugin of choice e.g LDAP only.
16 However, if you do this, and your external authentication tools fails,
16 However, if you do this, and your external authentication tools fails,
17 accessing |RCE| will be blocked unless a fallback plugin is
17 accessing |RCE| will be blocked unless a fallback plugin is
18 enabled via :file: rhodecode.ini
18 enabled via :file: rhodecode.ini
19
19
20
20
21 |RCE| comes with the following user authentication management plugins:
21 |RCE| comes with the following user authentication management plugins:
22
22
23
23
24 .. toctree::
24 .. toctree::
25
25
26 auth-token
26 auth-token
27 auth-ldap
27 auth-ldap
28 auth-ldap-groups
28 auth-ldap-groups
29 auth-saml-generic
29 auth-saml-generic
30 auth-saml-onelogin
30 auth-saml-onelogin
31 auth-saml-duosecurity
31 auth-saml-duosecurity
32 auth-saml-azure
32 auth-crowd
33 auth-crowd
33 auth-pam
34 auth-pam
34 ssh-connection
35 ssh-connection
@@ -1,153 +1,154 b''
1 # Copyright (C) 2012-2023 RhodeCode GmbH
1 # Copyright (C) 2012-2023 RhodeCode GmbH
2 #
2 #
3 # This program is free software: you can redistribute it and/or modify
3 # This program is free software: you can redistribute it and/or modify
4 # it under the terms of the GNU Affero General Public License, version 3
4 # it under the terms of the GNU Affero General Public License, version 3
5 # (only), as published by the Free Software Foundation.
5 # (only), as published by the Free Software Foundation.
6 #
6 #
7 # This program is distributed in the hope that it will be useful,
7 # This program is distributed in the hope that it will be useful,
8 # but WITHOUT ANY WARRANTY; without even the implied warranty of
8 # but WITHOUT ANY WARRANTY; without even the implied warranty of
9 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
9 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 # GNU General Public License for more details.
10 # GNU General Public License for more details.
11 #
11 #
12 # You should have received a copy of the GNU Affero General Public License
12 # You should have received a copy of the GNU Affero General Public License
13 # along with this program. If not, see <http://www.gnu.org/licenses/>.
13 # along with this program. If not, see <http://www.gnu.org/licenses/>.
14 #
14 #
15 # This program is dual-licensed. If you wish to learn more about the
15 # This program is dual-licensed. If you wish to learn more about the
16 # RhodeCode Enterprise Edition, including its added features, Support services,
16 # RhodeCode Enterprise Edition, including its added features, Support services,
17 # and proprietary license terms, please see https://rhodecode.com/licenses/
17 # and proprietary license terms, please see https://rhodecode.com/licenses/
18
18
19 import logging
19 import logging
20 import collections
20 import collections
21
21
22 from pyramid.exceptions import ConfigurationError
22 from pyramid.exceptions import ConfigurationError
23
23
24 from rhodecode.lib.utils2 import safe_str
24 from rhodecode.lib.utils2 import safe_str
25 from rhodecode.model.settings import SettingsModel
25 from rhodecode.model.settings import SettingsModel
26 from rhodecode.translation import _
26 from rhodecode.translation import _
27
27
28
28
29 log = logging.getLogger(__name__)
29 log = logging.getLogger(__name__)
30
30
31
31
32 class AuthnResourceBase(object):
32 class AuthnResourceBase(object):
33 __name__ = None
33 __name__ = None
34 __parent__ = None
34 __parent__ = None
35
35
36 def get_root(self):
36 def get_root(self):
37 current = self
37 current = self
38 while current.__parent__ is not None:
38 while current.__parent__ is not None:
39 current = current.__parent__
39 current = current.__parent__
40 return current
40 return current
41
41
42
42
43 class AuthnPluginResourceBase(AuthnResourceBase):
43 class AuthnPluginResourceBase(AuthnResourceBase):
44
44
45 def __init__(self, plugin):
45 def __init__(self, plugin):
46 self.plugin = plugin
46 self.plugin = plugin
47 self.__name__ = plugin.get_url_slug()
47 self.__name__ = plugin.get_url_slug()
48 self.display_name = plugin.get_display_name()
48 self.display_name = plugin.get_display_name()
49
49
50
50
51 class AuthnRootResource(AuthnResourceBase):
51 class AuthnRootResource(AuthnResourceBase):
52 """
52 """
53 This is the root traversal resource object for the authentication settings.
53 This is the root traversal resource object for the authentication settings.
54 """
54 """
55 is_root = True
55
56
56 def __init__(self):
57 def __init__(self):
57 self._store = collections.OrderedDict()
58 self._store = collections.OrderedDict()
58 self._resource_name_map = {}
59 self._resource_name_map = {}
59 self.display_name = _('Authentication Plugins')
60 self.display_name = _('Authentication Plugins')
60
61
61 def __getitem__(self, key):
62 def __getitem__(self, key):
62 """
63 """
63 Customized get item function to return only items (plugins) that are
64 Customized get item function to return only items (plugins) that are
64 activated.
65 activated.
65 """
66 """
66 if self._is_item_active(key):
67 if self._is_item_active(key):
67 return self._store[key]
68 return self._store[key]
68 else:
69 else:
69 raise KeyError('Authentication plugin "{}" is not active.'.format(
70 raise KeyError('Authentication plugin "{}" is not active.'.format(
70 key))
71 key))
71
72
72 def __iter__(self):
73 def __iter__(self):
73 for key in self._store.keys():
74 for key in self._store.keys():
74 if self._is_item_active(key):
75 if self._is_item_active(key):
75 yield self._store[key]
76 yield self._store[key]
76
77
77 def _is_item_active(self, key):
78 def _is_item_active(self, key):
78 activated_plugins = SettingsModel().get_auth_plugins()
79 activated_plugins = SettingsModel().get_auth_plugins()
79 plugin_id = self.get_plugin_id(key)
80 plugin_id = self.get_plugin_id(key)
80 return plugin_id in activated_plugins
81 return plugin_id in activated_plugins
81
82
82 def get_plugin_id(self, resource_name):
83 def get_plugin_id(self, resource_name):
83 """
84 """
84 Return the plugin id for the given traversal resource name.
85 Return the plugin id for the given traversal resource name.
85 """
86 """
86 # TODO: Store this info in the resource element.
87 # TODO: Store this info in the resource element.
87 return self._resource_name_map[resource_name]
88 return self._resource_name_map[resource_name]
88
89
89 def get_sorted_list(self, sort_key=None):
90 def get_sorted_list(self, sort_key=None):
90 """
91 """
91 Returns a sorted list of sub resources for displaying purposes.
92 Returns a sorted list of sub resources for displaying purposes.
92 """
93 """
93 def default_sort_key(resource):
94 def default_sort_key(resource):
94 return str.lower(safe_str(resource.display_name))
95 return str.lower(safe_str(resource.display_name))
95
96
96 active = [item for item in self]
97 active = [item for item in self]
97 return sorted(active, key=sort_key or default_sort_key)
98 return sorted(active, key=sort_key or default_sort_key)
98
99
99 def get_nav_list(self, sort=True):
100 def get_nav_list(self, sort=True):
100 """
101 """
101 Returns a sorted list of resources for displaying the navigation.
102 Returns a sorted list of resources for displaying the navigation.
102 """
103 """
103 if sort:
104 if sort:
104 nav_list = self.get_sorted_list()
105 nav_list = self.get_sorted_list()
105 else:
106 else:
106 nav_list = [item for item in self]
107 nav_list = [item for item in self]
107
108
108 nav_list.insert(0, self)
109 nav_list.insert(0, self)
109 return nav_list
110 return nav_list
110
111
111 def add_authn_resource(self, config, plugin_id, resource):
112 def add_authn_resource(self, config, plugin_id, resource):
112 """
113 """
113 Register a traversal resource as a sub element to the authentication
114 Register a traversal resource as a sub element to the authentication
114 settings. This method is registered as a directive on the pyramid
115 settings. This method is registered as a directive on the pyramid
115 configurator object and called by plugins.
116 configurator object and called by plugins.
116 """
117 """
117
118
118 def _ensure_unique_name(name, limit=100):
119 def _ensure_unique_name(name, limit=100):
119 counter = 1
120 counter = 1
120 current = name
121 current = name
121 while current in self._store.keys():
122 while current in self._store.keys():
122 current = f'{name}{counter}'
123 current = f'{name}{counter}'
123 counter += 1
124 counter += 1
124 if counter > limit:
125 if counter > limit:
125 raise ConfigurationError(
126 raise ConfigurationError(
126 'Cannot build unique name for traversal resource "%s" '
127 'Cannot build unique name for traversal resource "%s" '
127 'registered by plugin "%s"', name, plugin_id)
128 'registered by plugin "%s"', name, plugin_id)
128 return current
129 return current
129
130
130 # Allow plugin resources with identical names by rename duplicates.
131 # Allow plugin resources with identical names by rename duplicates.
131 unique_name = _ensure_unique_name(resource.__name__)
132 unique_name = _ensure_unique_name(resource.__name__)
132 if unique_name != resource.__name__:
133 if unique_name != resource.__name__:
133 log.warning('Name collision for traversal resource "%s" registered '
134 log.warning('Name collision for traversal resource "%s" registered '
134 'by authentication plugin "%s"', resource.__name__,
135 'by authentication plugin "%s"', resource.__name__,
135 plugin_id)
136 plugin_id)
136 resource.__name__ = unique_name
137 resource.__name__ = unique_name
137
138
138 log.debug('Register traversal resource "%s" for plugin "%s"',
139 log.debug('Register traversal resource "%s" for plugin "%s"',
139 unique_name, plugin_id)
140 unique_name, plugin_id)
140 self._resource_name_map[unique_name] = plugin_id
141 self._resource_name_map[unique_name] = plugin_id
141 resource.__parent__ = self
142 resource.__parent__ = self
142 self._store[unique_name] = resource
143 self._store[unique_name] = resource
143
144
144
145
145 root = AuthnRootResource()
146 root = AuthnRootResource()
146
147
147
148
148 def root_factory(request=None):
149 def root_factory(request=None):
149 """
150 """
150 Returns the root traversal resource instance used for the authentication
151 Returns the root traversal resource instance used for the authentication
151 settings route.
152 settings route.
152 """
153 """
153 return root
154 return root
@@ -1,122 +1,127 b''
1 <%inherit file="/base/base.mako"/>
1 <%inherit file="/base/base.mako"/>
2
2
3 <%def name="title()">
3 <%def name="title()">
4 ${_('Authentication Settings')}
4 ${_('Authentication Settings')}
5 %if c.rhodecode_name:
5 %if c.rhodecode_name:
6 &middot; ${h.branding(c.rhodecode_name)}}
6 &middot; ${h.branding(c.rhodecode_name)}}
7 %endif
7 %endif
8 </%def>
8 </%def>
9
9
10 <%def name="breadcrumbs_links()"></%def>
10 <%def name="breadcrumbs_links()"></%def>
11
11
12 <%def name="menu_bar_nav()">
12 <%def name="menu_bar_nav()">
13 ${self.menu_items(active='admin')}
13 ${self.menu_items(active='admin')}
14 </%def>
14 </%def>
15
15
16 <%def name="menu_bar_subnav()">
16 <%def name="menu_bar_subnav()">
17 ${self.admin_menu(active='authentication')}
17 ${self.admin_menu(active='authentication')}
18 </%def>
18 </%def>
19
19
20 <%def name="main()">
20 <%def name="main()">
21
21
22 <div class="box">
22 <div class="box">
23
23
24 <div class='sidebar-col-wrapper'>
24 <div class='sidebar-col-wrapper'>
25
25
26 <div class="sidebar">
26 <div class="sidebar">
27 <ul class="nav nav-pills nav-stacked">
27 <ul class="nav nav-pills nav-stacked">
28 % for item in resource.get_root().get_nav_list():
28 % for item in resource.get_root().get_nav_list():
29
29 <li ${('class=active' if item == resource else '')}>
30 <li ${('class=active' if item == resource else '')}>
31 % if getattr(item, 'is_root', False):
30 <a href="${request.resource_path(item, route_name='auth_home')}">${item.display_name}</a>
32 <a href="${request.resource_path(item, route_name='auth_home')}">${item.display_name}</a>
33 % else:
34 <a style="padding-left: 10px" href="${request.resource_path(item, route_name='auth_home')}">${item.display_name}</a>
35 % endif
31 </li>
36 </li>
32 % endfor
37 % endfor
33 </ul>
38 </ul>
34 </div>
39 </div>
35
40
36 <div class="main-content-full-width">
41 <div class="main-content-full-width">
37 ${h.secure_form(request.resource_path(resource, route_name='auth_home'), request=request)}
42 ${h.secure_form(request.resource_path(resource, route_name='auth_home'), request=request)}
38 <div class="panel panel-default">
43 <div class="panel panel-default">
39
44
40 <div class="panel-heading">
45 <div class="panel-heading">
41 <h3 class="panel-title">${_("Enabled and Available Plugins")}</h3>
46 <h3 class="panel-title">${_("Enabled and Available Plugins")}</h3>
42 </div>
47 </div>
43
48
44 <div class="panel-body">
49 <div class="panel-body">
45
50
46
51
47 <div class="label">${_("Ordered Activated Plugins")}</div>
52 <div class="label">${_("Ordered Activated Plugins")}</div>
48 <div class="textarea text-area editor">
53 <div class="textarea text-area editor">
49 ${h.textarea('auth_plugins',cols=120,rows=20,class_="medium")}
54 ${h.textarea('auth_plugins',cols=120,rows=20,class_="medium")}
50 </div>
55 </div>
51 <div class="field">
56 <div class="field">
52 <p class="help-block pre-formatting">${_('List of plugins, separated by commas.'
57 <p class="help-block pre-formatting">${_('List of plugins, separated by commas.'
53 '\nThe order of the plugins is also the order in which '
58 '\nThe order of the plugins is also the order in which '
54 'RhodeCode Enterprise will try to authenticate a user.')}
59 'RhodeCode Enterprise will try to authenticate a user.')}
55 </p>
60 </p>
56 </div>
61 </div>
57
62
58 <table class="rctable">
63 <table class="rctable">
59 <th>${_('Activate')}</th>
64 <th>${_('Activate')}</th>
60 <th>${_('Plugin Name')}</th>
65 <th>${_('Plugin Name')}</th>
61 <th>${_('Documentation')}</th>
66 <th>${_('Documentation')}</th>
62 <th>${_('Plugin ID')}</th>
67 <th>${_('Plugin ID')}</th>
63 <th>${_('Enabled')}</th>
68 <th>${_('Enabled')}</th>
64 %for plugin in available_plugins:
69 %for plugin in available_plugins:
65 <tr class="${('inactive' if (not plugin.is_active() and plugin.get_id() in enabled_plugins) else '')}">
70 <tr class="${('inactive' if (not plugin.is_active() and plugin.get_id() in enabled_plugins) else '')}">
66 <td>
71 <td>
67 <span plugin_id="${plugin.get_id()}" class="toggle-plugin btn ${('btn-success' if plugin.get_id() in enabled_plugins else '')}">
72 <span plugin_id="${plugin.get_id()}" class="toggle-plugin btn ${('btn-success' if plugin.get_id() in enabled_plugins else '')}">
68 ${(_('activated') if plugin.get_id() in enabled_plugins else _('not active'))}
73 ${(_('activated') if plugin.get_id() in enabled_plugins else _('not active'))}
69 </span>
74 </span>
70 </td>
75 </td>
71 <td>${plugin.get_display_name()}</td>
76 <td>${plugin.get_display_name()}</td>
72 <td>
77 <td>
73 % if plugin.docs():
78 % if plugin.docs():
74 <a href="${plugin.docs()}">docs</a>
79 <a href="${plugin.docs()}">docs</a>
75 % endif
80 % endif
76 </td>
81 </td>
77 <td>${plugin.get_id()}</td>
82 <td>${plugin.get_id()}</td>
78 <td>${h.bool2icon(plugin.is_active(),show_at_false=False)}</td>
83 <td>${h.bool2icon(plugin.is_active(),show_at_false=False)}</td>
79 </tr>
84 </tr>
80 %endfor
85 %endfor
81 </table>
86 </table>
82
87
83 <div class="buttons">
88 <div class="buttons">
84 ${h.submit('save',_('Save'),class_="btn")}
89 ${h.submit('save',_('Save'),class_="btn")}
85 </div>
90 </div>
86 </div>
91 </div>
87 </div>
92 </div>
88 ${h.end_form()}
93 ${h.end_form()}
89 </div>
94 </div>
90 </div>
95 </div>
91 </div>
96 </div>
92
97
93 <script>
98 <script>
94 $('.toggle-plugin').click(function(e){
99 $('.toggle-plugin').click(function(e){
95 var auth_plugins_input = $('#auth_plugins');
100 var auth_plugins_input = $('#auth_plugins');
96 var elems = [];
101 var elems = [];
97
102
98 $.each(auth_plugins_input.val().split(',') , function (index, element) {
103 $.each(auth_plugins_input.val().split(',') , function (index, element) {
99 if (element !== "") {
104 if (element !== "") {
100 elems.push(element.strip())
105 elems.push(element.strip())
101 }
106 }
102 });
107 });
103
108
104 var cur_button = e.currentTarget;
109 var cur_button = e.currentTarget;
105 var plugin_id = $(cur_button).attr('plugin_id');
110 var plugin_id = $(cur_button).attr('plugin_id');
106 if($(cur_button).hasClass('btn-success')){
111 if($(cur_button).hasClass('btn-success')){
107 elems.splice(elems.indexOf(plugin_id), 1);
112 elems.splice(elems.indexOf(plugin_id), 1);
108 auth_plugins_input.val(elems.join(',\n'));
113 auth_plugins_input.val(elems.join(',\n'));
109 $(cur_button).removeClass('btn-success');
114 $(cur_button).removeClass('btn-success');
110 cur_button.innerHTML = _gettext('not active');
115 cur_button.innerHTML = _gettext('not active');
111 }
116 }
112 else{
117 else{
113 if (elems.indexOf(plugin_id) === -1) {
118 if (elems.indexOf(plugin_id) === -1) {
114 elems.push(plugin_id);
119 elems.push(plugin_id);
115 }
120 }
116 auth_plugins_input.val(elems.join(',\n'));
121 auth_plugins_input.val(elems.join(',\n'));
117 $(cur_button).addClass('btn-success');
122 $(cur_button).addClass('btn-success');
118 cur_button.innerHTML = _gettext('activated');
123 cur_button.innerHTML = _gettext('activated');
119 }
124 }
120 });
125 });
121 </script>
126 </script>
122 </%def>
127 </%def>
@@ -1,139 +1,146 b''
1 <%inherit file="/base/base.mako"/>
1 <%inherit file="/base/base.mako"/>
2
2
3 <%def name="title()">
3 <%def name="title()">
4 ${_('Authentication Settings')}
4 ${_('Authentication Settings')}
5 %if c.rhodecode_name:
5 %if c.rhodecode_name:
6 &middot; ${h.branding(c.rhodecode_name)}}
6 &middot; ${h.branding(c.rhodecode_name)}}
7 %endif
7 %endif
8 </%def>
8 </%def>
9
9
10 <%def name="breadcrumbs_links()">
10 <%def name="breadcrumbs_links()">
11 ${h.link_to(_('Admin'),h.route_path('admin_home'))}
11 ${h.link_to(_('Admin'),h.route_path('admin_home'))}
12 &raquo;
12 &raquo;
13 ${h.link_to(_('Authentication Plugins'),request.resource_path(resource.__parent__, route_name='auth_home'))}
13 ${h.link_to(_('Authentication Plugins'),request.resource_path(resource.__parent__, route_name='auth_home'))}
14 &raquo;
14 &raquo;
15 ${resource.display_name}
15 ${resource.display_name}
16 </%def>
16 </%def>
17
17
18 <%def name="menu_bar_nav()">
18 <%def name="menu_bar_nav()">
19 ${self.menu_items(active='admin')}
19 ${self.menu_items(active='admin')}
20 </%def>
20 </%def>
21
21
22 <%def name="menu_bar_subnav()">
22 <%def name="menu_bar_subnav()">
23 ${self.admin_menu(active='authentication')}
23 ${self.admin_menu(active='authentication')}
24 </%def>
24 </%def>
25
25
26 <%def name="main()">
26 <%def name="main()">
27
27
28 <div class="box">
28 <div class="box">
29
29
30 <div class='sidebar-col-wrapper'>
30 <div class='sidebar-col-wrapper'>
31
31
32 <div class="sidebar">
32 <div class="sidebar">
33 <ul class="nav nav-pills nav-stacked">
33 <ul class="nav nav-pills nav-stacked">
34 % for item in resource.get_root().get_nav_list():
34 % for item in resource.get_root().get_nav_list():
35 <li ${('class=active' if item == resource else '')}>
35 <li ${('class=active' if item == resource else '')}>
36 <a href="${request.resource_path(item, route_name='auth_home')}">${item.display_name}</a>
36 <a href="${request.resource_path(item, route_name='auth_home')}">${item.display_name}</a>
37 </li>
37 </li>
38 % endfor
38 % endfor
39 </ul>
39 </ul>
40 </div>
40 </div>
41
41
42 <div class="main-content-full-width">
42 <div class="main-content-full-width">
43 <div class="panel panel-default">
43 <div class="panel panel-default">
44 <div class="panel-heading">
44 <div class="panel-heading">
45 <h3 class="panel-title">${_('Plugin')}: ${resource.display_name}</h3>
45 <h3 class="panel-title">${_('Plugin')}: ${resource.display_name}</h3>
46 </div>
46 </div>
47 <div class="panel-body">
47 <div class="panel-body">
48 <div class="plugin_form">
48 <div class="plugin_form">
49 <div class="fields">
49 <div class="fields">
50 ${h.secure_form(request.resource_path(resource, route_name='auth_home'), request=request)}
50 ${h.secure_form(request.resource_path(resource, route_name='auth_home'), request=request)}
51 <div class="form">
51 <div class="form">
52
52
53 ## Allow derived templates to add something above the form
54 ## input fields
55 %if hasattr(next, 'above_form_fields'):
56 ${next.above_form_fields()}
57 %endif
58
59 <h4>${_('Plugin Configuration')}</h4>
53 %for node in plugin.get_settings_schema():
60 %for node in plugin.get_settings_schema():
54 <%
61 <%
55 label_to_type = {'label-checkbox': 'bool', 'label-textarea': 'textarea'}
62 label_to_type = {'label-checkbox': 'bool', 'label-textarea': 'textarea'}
56 %>
63 %>
57
64
58 <div class="field">
65 <div class="field">
59 <div class="label ${label_to_type.get(node.widget)}"><label for="${node.name}">${node.title}</label></div>
66 <div class="label ${label_to_type.get(node.widget)}"><label for="${node.name}">${node.title}</label></div>
60 <div class="input">
67 <div class="input">
61 %if node.widget in ["string", "int", "unicode"]:
68 %if node.widget in ["string", "int", "unicode"]:
62 ${h.text(node.name, defaults.get(node.name), class_="large")}
69 ${h.text(node.name, defaults.get(node.name), class_="large")}
63 %elif node.widget == "password":
70 %elif node.widget == "password":
64 ${h.password(node.name, defaults.get(node.name), class_="large")}
71 ${h.password(node.name, defaults.get(node.name), class_="large")}
65 %elif node.widget == "bool":
72 %elif node.widget == "bool":
66 %if node.name == "global_2fa" and c.rhodecode_edition_id != "EE":
73 %if node.name == "global_2fa" and c.rhodecode_edition_id != "EE":
67 <input type="checkbox" disabled/>
74 <input type="checkbox" disabled/>
68 <%node.description = _('This feature is available in RhodeCode EE edition only. Contact {sales_email} to obtain a trial license.').format(sales_email='<a href="mailto:sales@rhodecode.com">sales@rhodecode.com</a>')%>
75 <%node.description = _('This feature is available in RhodeCode EE edition only. Contact {sales_email} to obtain a trial license.').format(sales_email='<a href="mailto:sales@rhodecode.com">sales@rhodecode.com</a>')%>
69 %else:
76 %else:
70 <div class="checkbox" >${h.checkbox(node.name, True, checked=defaults.get(node.name))}</div>
77 <div class="checkbox" >${h.checkbox(node.name, True, checked=defaults.get(node.name))}</div>
71 %endif
78 %endif
72 %elif node.widget == "select":
79 %elif node.widget == "select":
73 ${h.select(node.name, defaults.get(node.name), node.validator.choices, class_="select2AuthSetting")}
80 ${h.select(node.name, defaults.get(node.name), node.validator.choices, class_="select2AuthSetting")}
74 %elif node.widget == "select_with_labels":
81 %elif node.widget == "select_with_labels":
75 ${h.select(node.name, defaults.get(node.name), node.choices, class_="select2AuthSetting")}
82 ${h.select(node.name, defaults.get(node.name), node.choices, class_="select2AuthSetting")}
76 %elif node.widget == "textarea":
83 %elif node.widget == "textarea":
77 <div class="textarea" style="margin-left: 0px">${h.textarea(node.name, defaults.get(node.name), rows=10)}</div>
84 <div class="textarea" style="margin-left: 0px">${h.textarea(node.name, defaults.get(node.name), rows=10)}</div>
78 %elif node.widget == "readonly":
85 %elif node.widget == "readonly":
79 ${node.default}
86 ${node.default}
80 %else:
87 %else:
81 This field is of type ${node.typ}, which cannot be displayed. Must be one of [string|int|bool|select].
88 This field is of type ${node.typ}, which cannot be displayed. Must be one of [string|int|bool|select].
82 %endif
89 %endif
83
90
84 %if node.name in errors:
91 %if node.name in errors:
85 <span class="error-message">${errors.get(node.name)}</span>
92 <span class="error-message">${errors.get(node.name)}</span>
86 <br />
93 <br />
87 %endif
94 %endif
88 <p class="help-block pre-formatting">${node.description | n}</p>
95 <p class="help-block pre-formatting">${node.description | n}</p>
89 </div>
96 </div>
90 </div>
97 </div>
91 %endfor
98 %endfor
92
99
93 ## Allow derived templates to add something below the form
100 ## Allow derived templates to add something below the form
94 ## input fields
101 ## input fields
95 %if hasattr(next, 'below_form_fields'):
102 %if hasattr(next, 'below_form_fields'):
96 ${next.below_form_fields()}
103 ${next.below_form_fields()}
97 %endif
104 %endif
98
105
99 <div class="buttons">
106 <div class="buttons">
100 ${h.submit('save',_('Save'),class_="btn")}
107 ${h.submit('save',_('Save'),class_="btn")}
101 </div>
108 </div>
102
109
103 </div>
110 </div>
104 ${h.end_form()}
111 ${h.end_form()}
105 </div>
112 </div>
106 </div>
113 </div>
107
114
108 % if request.GET.get('schema'):
115 % if request.GET.get('schema'):
109 ## this is for development and creation of example configurations for documentation
116 ## this is for development and creation of example configurations for documentation
110 <pre>
117 <pre>
111 % for node in plugin.get_settings_schema():
118 % for node in plugin.get_settings_schema():
112 *option*: `${node.name}` => `${defaults.get(node.name)}`${'\n # '.join(['']+node.description.splitlines())}
119 *option*: `${node.name}` => `${defaults.get(node.name)}`${'\n # '.join(['']+node.description.splitlines())}
113
120
114 % endfor
121 % endfor
115 </pre>
122 </pre>
116
123
117 % endif
124 % endif
118
125
119 </div>
126 </div>
120 </div>
127 </div>
121 </div>
128 </div>
122
129
123 </div>
130 </div>
124 </div>
131 </div>
125
132
126
133
127 <script>
134 <script>
128 $(document).ready(function() {
135 $(document).ready(function() {
129 var select2Options = {
136 var select2Options = {
130 containerCssClass: 'drop-menu',
137 containerCssClass: 'drop-menu',
131 dropdownCssClass: 'drop-menu-dropdown',
138 dropdownCssClass: 'drop-menu-dropdown',
132 dropdownAutoWidth: true,
139 dropdownAutoWidth: true,
133 minimumResultsForSearch: -1
140 minimumResultsForSearch: -1
134 };
141 };
135 $('.select2AuthSetting').select2(select2Options);
142 $('.select2AuthSetting').select2(select2Options);
136
143
137 });
144 });
138 </script>
145 </script>
139 </%def>
146 </%def>
General Comments 0
You need to be logged in to leave comments. Login now