Add SAML 2.0 SSO.
Review Request #12254 — Created April 24, 2022 and submitted
This change adds SAML 2.0 support for single-sign-on authentication. It
includes a few major pieces:
- Infrastructure for SSO backends including registry, configuration
machinery, and URL registration. - Updates to settings forms to allow me to toggle some subforms based on
a checkbox enabler rather than via drop-downs. - SAML 2.0 backend which includes configuration, login/logout, and user
provisioning.
The vast majority of the settings available are specific to SAML,
including the various URLs and method settings. Because of some user
feedback we've already recieved, I've added a toggle to control the
behavior of user provisioning. In most cases, the person using this has
absolute trust in the integrity and correctness of their IdP, but in
some cases that may not be true. If the "username" parameter can not
necessarily be trusted, there's an option to force existing users to log
in with their Review Board password at least once.
Testing was done with a test application on onelogin.com with the
relevant configuration to authenticate to my server on localhost.
- Logged in with existing user that had a username match.
- Logged in with user that had an email match and saw correct detection
of the existing user. - Logged in with a user that had no existing match and saw provision
screen. Proceeded and was logged in with a new user with correct
name/email/etc. - Tested behavior of "require login" toggle.
- Logged out from onelogin portal and saw GET request to the SLS
endpoint which flushed the session and then redirected back to the
onelogin login page. - Tested authentication configuration page, enabling/disabling settings,
and making changes to settings. Tested behavior when the
python3-saml
package wasn't installed. - Tested text of button on login page, and that it redirected to the SSO
login flow. - Ran unit tests.
Summary | ID |
---|---|
bf918a95fe5de7d72edf7932c56b0d7e4c1f70f4 |
Description | From | Last Updated |
---|---|---|
Looks good. Since this is WIP, I won't give it a Ship It!, but we're ready to move onto the … |
chipx86 | |
Do we need to do this, or can we rely on lazy population in the registry? |
chipx86 | |
Blank line between these. |
chipx86 | |
extra_data is worth having, but I think we may want to include something specific for credential data that we'd never … |
chipx86 | |
Missing docstring. |
chipx86 | |
Rather than this format, cna we do: for _module, _backend_cls_name in (('saml.sso_backend', 'SAMLSSOBackend'),): ... Or define the list separately. |
chipx86 | |
Missing docs in this file. |
chipx86 | |
This should be after __init__. |
chipx86 | |
F821 undefined name 'ModuleNotFoundError' |
reviewbot | |
conf before contrib. |
chipx86 | |
404 before Response. |
chipx86 | |
These are in reverse order. |
chipx86 | |
These are in reverse order. |
chipx86 | |
Same with these. |
chipx86 | |
Missing docs. |
chipx86 | |
We should have some else case, even if that's just raising an exception. |
chipx86 | |
No need to .save() after .create(). |
chipx86 | |
Shouldn't have a trailing comma for a function call. |
chipx86 | |
Missing a Version Added. |
chipx86 | |
Missing a Version Added. We should put them in the functions as well. Same comments for other new modules. |
chipx86 | |
These should be swapped. |
chipx86 | |
Let's wrap any calls in an exception, in case any extension-provided backends (or ours) ever misbehave. |
chipx86 | |
Should we conditionally save ones with _enabled? |
chipx86 | |
Typo: flieds. |
chipx86 | |
Col: 40 Missing semicolon. |
reviewbot | |
Missing ; |
chipx86 | |
Col: 64 Missing semicolon. |
reviewbot | |
Missing ; |
chipx86 | |
Thes should be indented 1 space. No need for />. Same elsewhere. These apply to the other templates as well. |
chipx86 | |
F821 undefined name 'ModuleNotFoundError' |
reviewbot | |
F401 'django.contrib.auth.login' imported but unused |
reviewbot | |
F401 'reviewboard.accounts.backends.standard.StandardAuthBackend' imported but unused |
reviewbot | |
F401 'django.utils.translation.gettext_lazy as _' imported but unused |
reviewbot | |
"Single Sign-On" is the more "official" way it's written. Let's use that everywhere. |
chipx86 | |
We use "Identity Provider", "IdP", and "identity provider" in the document. We should stick with one term and capitalization. We … |
chipx86 | |
What do you think about breaking this down in bullet point form, like: You Identity Provider should provide the following: … |
chipx86 | |
We should probably make it clear that these are examples and make sure they don't link: Example: ``https://.../` Worth describing … |
chipx86 | |
Trying to start moving our initial signal setup into the AppConfig and signal_handlers.py, so we can avoid side-effects on module … |
chipx86 | |
I have a couple of additional thoughts regarding this model. These are pure discussion topics. I don't have concrete answers. … |
chipx86 | |
I hope 64 is fine, but I wonder if we might want to give some more breathing room. Maybe 128? |
chipx86 | |
We could probably put that in the help text. |
chipx86 | |
If we do add a LocalSite relation, we'll need that in here. However, I'm not sure that we want to … |
chipx86 | |
Let's standardize on "Single Sign-On". |
chipx86 | |
We can probably just make this a urls = [] attribute by default, and let subclasses decide whether to use … |
chipx86 | |
Can we break this down into a numbered list of items, for readability? This should also document what the second … |
chipx86 | |
Since this is a new registry, we can probably avoid entrypoints altogether, just require extensions to register items. |
chipx86 | |
If we don't need to support entrypoints, can we remove this? |
chipx86 | |
We can probably remove this blank line. |
chipx86 | |
These can probably begin on the include( line. |
chipx86 | |
I wonder if we could find a better place for this, because there are other places where we're going to … |
chipx86 | |
This label should be in sentence casing. |
chipx86 | |
This label should be in sentence casing (unless "Issuer" is generally capitalized here). |
chipx86 | |
These labels should also be in sentence casing. |
chipx86 | |
"Identity Provider"? |
chipx86 | |
Do we want to remove these? |
chipx86 | |
Each of these could start on the path( line. |
chipx86 | |
Same notes as on the base implementation. |
chipx86 | |
We may want to say "... and restart the web server" |
chipx86 | |
Should this be @cached_property? |
chipx86 | |
Should this be @cached_property? |
chipx86 | |
No need for str() here (unless we're testing via spies an want to ease checking this argument's value). |
chipx86 | |
Is this related to the TODO above? Should we drop this, document this? |
chipx86 | |
Can we use :term: for things like IdP, and define in glossary.rst? |
chipx86 | |
Worth starting to use Enum for these things? (Maybe not -- just throwing this out there.) |
chipx86 | |
This will need a Raises: |
chipx86 | |
Can we put quotes around the values? |
chipx86 | |
Returns goes before Raises. |
chipx86 | |
Can we provide the username in question as an argument to this? |
chipx86 | |
Can you wrap find_suggested_username in :py:func:? |
chipx86 | |
I think I wrote this initially, but it might make sense to limit this to one database query: q = … |
chipx86 | |
Swap these. |
chipx86 | |
For readability, can we move the name= to the next line? This all kind of blurs together. |
chipx86 | |
This should go above the previous sso imports. |
chipx86 | |
No trailing period (here and elsewhere). |
chipx86 | |
To reduce the amount of code and repeated attribute lookups, can we pull out siteconfig into a local variable? |
chipx86 | |
To just reduce database hits during tests, let's just fetch all linked accounts as list(...), and then we can check … |
chipx86 | |
Version Added? |
chipx86 | |
We do this whole fetch of everything leading up to 'fields' up to twice per forloop iteration. Let's pull this … |
chipx86 | |
How was load() being called before? Are we at risk of calling it twice now? |
chipx86 | |
We do so many of these. Wonder if it'd make sense to have a private function that yields sso_backend_id, form, … |
chipx86 | |
Leftover debugging. |
chipx86 | |
Can we remove the blank line? |
chipx86 | |
No need for /> anymore. |
chipx86 | |
Can we remove the blank line? |
chipx86 | |
Can we remove the blank line? |
chipx86 | |
No need for the />. |
chipx86 | |
Can we remove the blank line? |
chipx86 | |
Can we remove the blank line? |
chipx86 | |
No need for the /> |
chipx86 | |
Can we remove the blank line? |
chipx86 | |
F401 'django_evolution.mutations.AddField' imported but unused |
reviewbot | |
E402 module level import not at top of file |
reviewbot | |
Can this be super()? |
chipx86 | |
Since we've eliminated the entrypoint support, we no longer need this. |
chipx86 | |
Can this be super()? |
chipx86 | |
Can this be super()? |
chipx86 | |
Can this be super()? |
chipx86 | |
Can this be super()? |
chipx86 | |
Can this be super()? |
chipx86 | |
We should probably get that into Asana for tracking. What's involved here? Can we address this for 5.0? |
chipx86 | |
Can this be super()? |
chipx86 | |
Can this be super()? |
chipx86 | |
Can this be super()? |
chipx86 | |
'djblets.registries.registry.LOAD_ENTRY_POINT' imported but unused Column: 1 Error code: F401 |
reviewbot | |
'djblets.db.query.get_object_or_none' imported but unused Column: 1 Error code: F401 |
reviewbot |
-
I think this all looks really good. There are a lot of moving pieces, so I'm not sure how much I've internalized (it would be nice to ultimately break this out into a change for the subform code, and then maybe SSO vs. SAML implementation), but nothing stands out as wrong.
I have a handful of comments in here. Most are things like doc fixes or style/ordering fixes, which I stopped providing because I know it's WIP. Only a few are on design.
-
-
-
extra_data
is worth having, but I think we may want to include something specific for credential data that we'd never want to expose via the API.HostingServiceAccount
has adata = JSONField()
where those go. Maybe aservice_data =
would be appropriate. -
-
Rather than this format, cna we do:
for _module, _backend_cls_name in (('saml.sso_backend', 'SAMLSSOBackend'),): ...
Or define the list separately.
-
-
-
-
-
-
-
-
-
-
-
-
-
Missing a
Version Added
. We should put them in the functions as well.Same comments for other new modules.
-
-
Let's wrap any calls in an exception, in case any extension-provided backends (or ours) ever misbehave.
-
-
-
-
-
Thes should be indented 1 space.
No need for
/>
. Same elsewhere.These apply to the other templates as well.
- Description:
-
This is the preliminary change for adding SAML 2.0 authentication. It
includes a few major pieces: - Infrastructure for SSO backends including registry, configuration
machinery, and URL registration.
- Updates to settings forms to allow me to toggle some subforms based on
a checkbox enabler rather than via drop-downs.
- SAML 2.0 backend which includes configuration, login/logout, and user
provisioning.
The vast majority of the settings available are specific to SAML,
including the various URLs and method settings. Because of some user feedback we've already recieved, I've added a toggle to control the behavior of user provisioning. In most cases, the person using this has absolute trust in the integrity and correctness of their IdP, but in some cases that may not be true. If the "username" parameter can not necessarily be trusted, there's an option to force existing users to log in with their Review Board password at least once. What's left to do:
- "Login with SAML" button on the login screen.
- Lots more unit testing.
- Some refactoring of the link-user view to extract common functionality
for other backends.
- User/admin manual.
- Ensure codebase docs are correct and consistent.
- - Test behavior when python3-saml isn't installed.
- Infrastructure for SSO backends including registry, configuration
- Testing Done:
-
Testing was done with a test application on onelogin.com with the
relevant configuration to authenticate to my server on localhost. - Logged in with existing user that had a username match.
- Logged in with user that had an email match and saw correct detection
of the existing user.
- Logged in with a user that had no existing match and saw provision
screen. Proceeded and was logged in with a new user with correct
name/email/etc.
- Tested behavior of "require login" toggle.
- Logged out from onelogin portal and saw GET request to the SLS
endpoint which flushed the session and then redirected back to the
onelogin login page.
+ - Tested authentication configuration page, enabling/disabling settings,
and making changes to settings. Tested behavior when the
python3-saml
package wasn't installed.
- Commits:
-
Summary ID 93052180b2f08ac863c6fc17e843abe1978382a7 a03de0ec350f55ef6b238bf5bc7fda62b3884103
- Change Summary:
-
Switch to
ImportError
for import test, since that's a parent class ofModuleNotFoundError
, and works with python 2.7 and the version of flake8 we're running. - Commits:
-
Summary ID a03de0ec350f55ef6b238bf5bc7fda62b3884103 81ee98de7add6622dce178d20f52510a02c2405a
Checks run (2 succeeded)
- Change Summary:
-
- Docstrings
- Use common
login_user
method.
- Description:
-
This is the preliminary change for adding SAML 2.0 authentication. It
includes a few major pieces: - Infrastructure for SSO backends including registry, configuration
machinery, and URL registration.
- Updates to settings forms to allow me to toggle some subforms based on
a checkbox enabler rather than via drop-downs.
- SAML 2.0 backend which includes configuration, login/logout, and user
provisioning.
The vast majority of the settings available are specific to SAML,
including the various URLs and method settings. Because of some user feedback we've already recieved, I've added a toggle to control the behavior of user provisioning. In most cases, the person using this has absolute trust in the integrity and correctness of their IdP, but in some cases that may not be true. If the "username" parameter can not necessarily be trusted, there's an option to force existing users to log in with their Review Board password at least once. What's left to do:
- "Login with SAML" button on the login screen.
- Lots more unit testing.
- Some refactoring of the link-user view to extract common functionality
for other backends.
- User/admin manual.
- - Ensure codebase docs are correct and consistent.
- Infrastructure for SSO backends including registry, configuration
- Commits:
-
Summary ID 81ee98de7add6622dce178d20f52510a02c2405a 580aaefd8444bbe4036e8e449530b45987bcea2b
- Commits:
-
Summary ID 580aaefd8444bbe4036e8e449530b45987bcea2b 5c529a68bc0c229a5dab3098c639a19932ecf4f6
Checks run (2 succeeded)
- Change Summary:
-
- Added login button.
- Added docs to admin manual.
- Validation for settings form fields.
- Removed configurable NameID format, since we require NameID to be the username (and anything else doesn't make sense for us).
- Added a bunch of unit tests.
- Description:
-
This is the preliminary change for adding SAML 2.0 authentication. It
includes a few major pieces: - Infrastructure for SSO backends including registry, configuration
machinery, and URL registration.
- Updates to settings forms to allow me to toggle some subforms based on
a checkbox enabler rather than via drop-downs.
- SAML 2.0 backend which includes configuration, login/logout, and user
provisioning.
The vast majority of the settings available are specific to SAML,
including the various URLs and method settings. Because of some user feedback we've already recieved, I've added a toggle to control the behavior of user provisioning. In most cases, the person using this has absolute trust in the integrity and correctness of their IdP, but in some cases that may not be true. If the "username" parameter can not necessarily be trusted, there's an option to force existing users to log in with their Review Board password at least once. ~ What's left to do:
~ What's left to do:
+ - A bit more unit testing. ~ - "Login with SAML" button on the login screen.
~ - Lots more unit testing.
~ - Some refactoring of the link-user view to extract common functionality
for other backends.
~ - User/admin manual.
~ Testing Done:
~ Testing was done with a test application on onelogin.com with the ~ relevant configuration to authenticate to my server on localhost. ~ + - Logged in with existing user that had a username match.
+ - Logged in with user that had an email match and saw correct detection
of the existing user.
+ - Logged in with a user that had no existing match and saw provision
screen. Proceeded and was logged in with a new user with correct
name/email/etc.
+ - Tested behavior of "require login" toggle.
+ - Logged out from onelogin portal and saw GET request to the SLS
endpoint which flushed the session and then redirected back to the
onelogin login page.
+ - Tested authentication configuration page, enabling/disabling settings,
and making changes to settings. Tested behavior when the
python3-saml
package wasn't installed.
+ - Tested text of button on login page, and that it redirected to the SSO
login flow.
+ - Ran unit tests.
- Infrastructure for SSO backends including registry, configuration
- Commits:
-
Summary ID 5c529a68bc0c229a5dab3098c639a19932ecf4f6 f4d058c3309ec6c74e5b7d8c0640b2796b50b378 - Diff:
-
Revision 6 (+4432 -46)
Checks run (2 succeeded)
- Change Summary:
-
Fix up description/testing done.
- Description:
-
This is the preliminary change for adding SAML 2.0 authentication. It
includes a few major pieces: - Infrastructure for SSO backends including registry, configuration
machinery, and URL registration.
- Updates to settings forms to allow me to toggle some subforms based on
a checkbox enabler rather than via drop-downs.
- SAML 2.0 backend which includes configuration, login/logout, and user
provisioning.
The vast majority of the settings available are specific to SAML,
including the various URLs and method settings. Because of some user feedback we've already recieved, I've added a toggle to control the behavior of user provisioning. In most cases, the person using this has absolute trust in the integrity and correctness of their IdP, but in some cases that may not be true. If the "username" parameter can not necessarily be trusted, there's an option to force existing users to log in with their Review Board password at least once. What's left to do:
- A bit more unit testing. - - Testing Done:
- Testing was done with a test application on onelogin.com with the - relevant configuration to authenticate to my server on localhost. - - - Logged in with existing user that had a username match.
- - Logged in with user that had an email match and saw correct detection
of the existing user.
- - Logged in with a user that had no existing match and saw provision
screen. Proceeded and was logged in with a new user with correct
name/email/etc.
- - Tested behavior of "require login" toggle.
- - Logged out from onelogin portal and saw GET request to the SLS
endpoint which flushed the session and then redirected back to the
onelogin login page.
- - Tested authentication configuration page, enabling/disabling settings,
and making changes to settings. Tested behavior when the
python3-saml
package wasn't installed.
- - Tested text of button on login page, and that it redirected to the SSO
login flow.
- - Ran unit tests.
- Infrastructure for SSO backends including registry, configuration
- Testing Done:
-
Testing was done with a test application on onelogin.com with the
relevant configuration to authenticate to my server on localhost. - Logged in with existing user that had a username match.
- Logged in with user that had an email match and saw correct detection
of the existing user.
- Logged in with a user that had no existing match and saw provision
screen. Proceeded and was logged in with a new user with correct
name/email/etc.
- Tested behavior of "require login" toggle.
- Logged out from onelogin portal and saw GET request to the SLS
endpoint which flushed the session and then redirected back to the
onelogin login page.
- Tested authentication configuration page, enabling/disabling settings,
and making changes to settings. Tested behavior when the
python3-saml
package wasn't installed.
+ - Tested text of button on login page, and that it redirected to the SSO
login flow.
+ - Ran unit tests.
- Change Summary:
-
Remove debug print statements.
- Commits:
-
Summary ID f4d058c3309ec6c74e5b7d8c0640b2796b50b378 b8d560c0c13852a8b3042ef74e4fe44bff49d503 - Diff:
-
Revision 7 (+4420 -46)
Checks run (2 succeeded)
- Change Summary:
-
Out of WIP.
- Summary:
-
[WIP] Add SAML 2.0 SSO.Add SAML 2.0 SSO.
- Description:
-
~ This is the preliminary change for adding SAML 2.0 authentication. It
~ This change adds SAML 2.0 support for single-sign-on authentication. It
includes a few major pieces: - Infrastructure for SSO backends including registry, configuration
machinery, and URL registration.
- Updates to settings forms to allow me to toggle some subforms based on
a checkbox enabler rather than via drop-downs.
- SAML 2.0 backend which includes configuration, login/logout, and user
provisioning.
The vast majority of the settings available are specific to SAML,
including the various URLs and method settings. Because of some user feedback we've already recieved, I've added a toggle to control the behavior of user provisioning. In most cases, the person using this has absolute trust in the integrity and correctness of their IdP, but in some cases that may not be true. If the "username" parameter can not necessarily be trusted, there's an option to force existing users to log in with their Review Board password at least once. - - What's left to do:
- - A bit more unit testing. - Infrastructure for SSO backends including registry, configuration
- Commits:
-
Summary ID b8d560c0c13852a8b3042ef74e4fe44bff49d503 e41fe7a85fc282934718c0587c9b80d55b1e5ee2 - Diff:
-
Revision 8 (+4838 -46)
- Commits:
-
Summary ID e41fe7a85fc282934718c0587c9b80d55b1e5ee2 62545c8cc6f7b3ac619978ef3559f1f9a4abc012 - Diff:
-
Revision 9 (+4836 -46)
Checks run (2 succeeded)
-
This is great. Thanks again for taking this on!
Lots of comments in here, since it's a large. Mostly style, some doc suggestions, food-for-thought, and some things you're more than welcome to defer (future code improvement stuff). There is one larger topic about
LinkedAccount
model fields that I think we'll want to figure out. -
-
We use "Identity Provider", "IdP", and "identity provider" in the document. We should stick with one term and capitalization.
We could wrap each in
:term:
and then define it more closely inglossary.rst
, if that's worth it. That at least would also allow us to group the variations (Identity Provider
,IdP
). -
What do you think about breaking this down in bullet point form, like:
You Identity Provider should provide the following: 1. URLs to fill out for the Issuer and SAML/SLO endpoints. 2. A copy of your X.509 certificate. 3. ...
-
We should probably make it clear that these are examples and make sure they don't link:
Example: ``https://.../`
Worth describing these at all?
-
Trying to start moving our initial signal setup into the
AppConfig
andsignal_handlers.py
, so we can avoid side-effects on module import. I just did this with /r/12299/, for reference. Can we adopt that pattern here? -
I have a couple of additional thoughts regarding this model.
These are pure discussion topics. I don't have concrete answers.
Local Sites?
Do we want to bind this to a
LocalSite
?An argument for that would be that if an organization shuts down their, say, RBCommons account, and a user retains their linked account, both we and they retain some link to an account that the organization may have expected to have been deleted.
Having a
LocalSite
relation would mean that a user would have to link up their accounts per-LocalSite
, but that's probably a lot less common and maybe even preferable.Linked account type
I think it'd be really useful to be able to identify the type of a linked account. I know we can query by service, but something more broad can be useful for linked account management.
I don't know what this would look like, or at what level we would want to clarify it.
Maybe we differentiate "auth" from "chat" from "scm" or something.
Or maybe instead of/in addition, we want to bind an integration ID, for any integrations that will use this.
Again, no idea, but for querying/management purposes, I think we'd want something beyond
service_id
. -
-
-
If we do add a
LocalSite
relation, we'll need that in here.However, I'm not sure that we want to limit 1 user account per service ID. Instead, do we want this to be
('service_user_id', 'service_id')
? -
-
We can probably just make this a
urls = []
attribute by default, and let subclasses decide whether to use@property
. -
Can we break this down into a numbered list of items, for readability?
This should also document what the second item looks like if the first is
True
. -
Since this is a new registry, we can probably avoid entrypoints altogether, just require extensions to register items.
-
-
-
-
I wonder if we could find a better place for this, because there are other places where we're going to want X.509 certs to be validated (such as self-signed certs for repos/LDAP/etc. eventually).
We probably should have a
reviewboard.crypto
module, or even adjblets.crypto
. We currently have some crypto utils inreviewboard.scmtools.crypto_utils
, and we could put this in there for now, but it might be a good time to think about a better location.This does not have to be part of this change.
-
-
-
-
-
-
-
-
-
-
-
No need for
str()
here (unless we're testing via spies an want to ease checking this argument's value). -
-
-
-
-
-
-
-
-
I think I wrote this initially, but it might make sense to limit this to one database query:
q = Q() if username: q |= Q(username=username) q |= Q(email=email) | Q(username=alternate_username) return get_object_or_none(User, q)
Actually though, whether we do this or not, we can't rely on
get_object_or_none()
alone when queryingemail
, as that can match multiple users. We need to handle that case. -
-
-
-
-
To reduce the amount of code and repeated attribute lookups, can we pull out
siteconfig
into a local variable? -
To just reduce database hits during tests, let's just fetch all linked accounts as
list(...)
, and then we can check length and inspect the first result without further queries.Same below.
-
-
We do this whole fetch of everything leading up to
'fields'
up to twice per forloop iteration. Let's pull this out before the loop. That'll help it read a bit better, too. -
-
We do so many of these. Wonder if it'd make sense to have a private function that yields
sso_backend_id, form, enable_field_id
.Just a cleanup suggestion, but not critical.
-
-
-
-
-
-
-
-
-
-
- Change Summary:
-
- Made requested changes
- Change SAML request to get hostname/port from the configured server
URL rather than the request. This prevents issues with mismatched
URLs when the server is running internally on a different port than
the public endpoint. - Fix error reporting for ACS view to get useful messages instead of
just "invalid response".
- Commits:
-
Summary ID 62545c8cc6f7b3ac619978ef3559f1f9a4abc012 6ee8f3ec540f29f5410a07186a85b6e651f8fcc9 - Diff:
-
Revision 10 (+4898 -52)
- Commits:
-
Summary ID 6ee8f3ec540f29f5410a07186a85b6e651f8fcc9 00db71cadf9ebab745a02588c2811f7c3fedf5d2 - Diff:
-
Revision 11 (+4910 -54)
- Change Summary:
-
Remove unintentional changes
- Commits:
-
Summary ID 00db71cadf9ebab745a02588c2811f7c3fedf5d2 45e46fed821f2b3a7f1c1c7a3c0005efc6e5e0ae - Diff:
-
Revision 12 (+4898 -52)
Checks run (2 succeeded)
- Change Summary:
-
- Add documentation on authentication with RBTools (we have some in the RBTools manual too, but this is just an extra warning)
- Add error handling for when the assertion doesn't include email or name information.
- Commits:
-
Summary ID 45e46fed821f2b3a7f1c1c7a3c0005efc6e5e0ae 8e214fbfb7ade198e46b4c56e19553e2b3166816 - Diff:
-
Revision 13 (+4984 -52)
Checks run (2 succeeded)
- Commits:
-
Summary ID 8e214fbfb7ade198e46b4c56e19553e2b3166816 8244640bd790d9f37f972e082fd435bc1b493209