Updated uses of user ID to nullify on delete.
Added testing to cover deletion of user relations.
Added model factories to support changes and potential other tests.
Cleans existing ID references in the DB via migration.
As per PR #5800
* DB: Planned out new entity table format via migrations
* DB: Created entity migration logic
Made some other tweaks/fixes while testing.
* DB: Added change of entity relation columns to suit new entities table
* DB: Got most view queries working for new structure
* Entities: Started logic change to new structure
Updated base entity class, and worked through BaseRepo.
Need to go through other repos next.
Removed a couple of redundant interfaces as part of this since we can
move the logic onto the shared ContainerData model as needed.
* Entities: Been through repos to update for new format
* Entities: Updated repos to act on refreshed clones
Changes to core entity models are now done on clones to ensure clean
state before save, and those clones are returned back if changes are
needed after that action.
* Entities: Updated model classes & relations for changes
* Entities: Changed from *Data to a common "contents" system
Added smart loading from builder instances which should hydrate with
"contents()" loaded via join, while keeping the core model original.
* Entities: Moved entity description/covers to own non-model classes
Added back some interfaces.
* Entities: Removed use of contents system for data access
* Entities: Got most queries back to working order
* Entities: Reverted back to data from contents, fixed various issues
* Entities: Started addressing issues from tests
* Entities: Addressed further tests/issues
* Entities: Been through tests to get all passing in dev
Fixed issues and needed test changes along the way.
* Entities: Addressed phpstan errors
* Entities: Reviewed TODO notes
* Entities: Ensured book/shelf relation data removed on destroy
* Entities: Been through API responses & adjusted field visibility
* Entities: Added type index to massively improve query speed
Hardened things to enforce the intent that the guest account should not
be used for logins.
Currently this would not be allowed due to empty set password, and no
password fields on user edit forms, but an error could occur if the
login was attempted.
This adds:
- Handling to show normal invalid user warning on login instead of a
hash check error.
- Prevention of guest user via main login route, in the event that
inventive workarounds would be used by admins to set a password for
this account.
- Test for guest user login.
Added specific handling to show relevant error message when user
creation fails due to invite sending errors, while also returning user
to the form with previous input.
Includes test to cover.
For #5195
An empty (but valid formed) groups list provided via the OIDC ID token
would be considered as a lacking detail, and therefore trigger a lookup
to the userinfo endpoint in an attempt to get that information.
This fixes this to properly distinguish between not-provided and empty
state, to avoid userinfo where provided as valid but empty.
Includes test to cover.
For #5101
Review of #4913
Added testing to cover option.
Updated option so it can be used for a CA directory, or a CA file.
Updated option name to be somewhat abstracted from original underling
PHP option.
Tested against Jumpcloud.
Testing took hours due to instability which was due to these settings
sticking and being unstable on change until php process restart.
Also due to little documentation for these options.
X_TLS_CACERTDIR option needs cert files to be named via specific hashes
which can be achieved via c_rehash utility.
This also adds detail on STARTTLS failure, which took a long time to
discover due to little detail out there for deeper PHP LDAP debugging.
To not conflict with env variables, and to align with placeholders used
for PDF gen command.
Added test to cover, including old format supported for
back-compatibility.
For #4967
Wrapped userinfo response in its own class for additional handling and
validation.
Updated userdetails to take abstract claim data, to be populated by
either userinfo data or id token data.
Allows a proper defined object instead of an array an extracts related
logic out of OidcService.
Updated userinfo to only be called if we're missing details.
- Added endpoint validation to ensure HTTPS as per spec
- Added some missing types
- Removed redirectUri from OidcProviderSettings since it's not a
provider-based setting, but a setting for the oauth client, so
extracted that back to service.
Using the env LDAP_TLS_CACERTFILE to set a file to use to override
the CA CERT used to verify LDAPS connections. This is to make this
process easier for docker use.
BooksStack's OIDC Client requests the 'profile' and 'email' scope values
in order to have access to the 'name', 'email', and other claims. It
looks for these claims in the ID Token that is returned along with the
Access Token.
However, the OIDC-core specification section 5.4 [1] only requires that
the Provider include those claims in the ID Token *if* an Access Token is
not also issued. If an Access Token is issued, the Provider can leave out
those claims from the ID Token, and the Client is supposed to obtain them
by submitting the Access Token to the UserInfo Endpoint.
So I suppose it's just good luck that the OIDC Providers that BookStack
has been tested with just so happen to also stick those claims in the ID
Token even though they don't have to. But others (in particular:
https://login.infomaniak.com) don't do so, and require fetching the
UserInfo Endpoint.)
A workaround is currently possible by having the user write a theme with a
ThemeEvents::OIDC_ID_TOKEN_PRE_VALIDATE hook that fetches the UserInfo
Endpoint. This workaround isn't great, for a few reasons:
1. Asking the user to implement core parts of the OIDC protocol is silly.
2. The user either needs to re-fetch the .well-known/openid-configuration
file to discover the endpoint (adding yet another round-trip to each
login) or hard-code the endpoint, which is fragile.
3. The hook doesn't receive the HTTP client configuration.
So, have BookStack's OidcService fetch the UserInfo Endpoint and inject
those claims into the ID Token, if a UserInfo Endpoint is defined.
Two points about this:
- Injecting them into the ID Token's claims is the most obvious approach
given the current code structure; though I'm not sure it is the best
approach, perhaps it should instead fetch the user info in
processAuthorizationResponse() and pass that as an argument to
processAccessTokenCallback() which would then need a bit of
restructuring. But this made sense because it's also how the
ThemeEvents::OIDC_ID_TOKEN_PRE_VALIDATE hook works.
- OIDC *requires* that a UserInfo Endpoint exists, so why bother with
that "if a UserInfo Endpoint is defined" bit? Simply out of an
abundance of caution that there's an existing BookStack user that is
relying on it not fetching the UserInfo Endpoint in order to work with
a non-compliant OIDC Provider.
[1]: https://openid.net/specs/openid-connect-core-1_0.html#ScopeClaims