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