diff --git a/docs/source/endpoints/index.md b/docs/source/endpoints/index.md index 800b9f5286..2eb88c4de5 100644 --- a/docs/source/endpoints/index.md +++ b/docs/source/endpoints/index.md @@ -1,10 +1,10 @@ --- myst: html_meta: - "description": "Usage of the Plone REST API." - "property=og:description": "Usage of the Plone REST API." - "property=og:title": "Usage of the Plone REST API" - "keywords": "Plone, plone.restapi, REST, API, Usage" + "description": "Endpoints of the Plone REST API." + "property=og:description": "Endpoints of the Plone REST API." + "property=og:title": "Endpoints of the Plone REST API" + "keywords": "Plone, plone.restapi, REST, API, endpoints" --- (restapi-endpoints)= @@ -33,6 +33,7 @@ groups history linkintegrity locking +login navigation navroot actions diff --git a/docs/source/endpoints/login.md b/docs/source/endpoints/login.md new file mode 100644 index 0000000000..8541bb91be --- /dev/null +++ b/docs/source/endpoints/login.md @@ -0,0 +1,71 @@ +--- +myst: + html_meta: + "description": "The @login endpoint exposes the list of external authentication services that may be used in the Plone site." + "property=og:description": "The @login endpoint exposes the list of external authentication services that may be used in the Plone site." + "property=og:title": "@login for external authentication links" + "keywords": "Plone, plone.restapi, REST, API, login, authentication, external services" +--- + +# Login for external authentication links + +It is common to use add-ons that allow logging in to your site using third party services. +Such add-ons include using authentication services provided by KeyCloak, GitHub, or other OAuth2 or OpenID Connect enabled services. + +When you install one of these add-ons, it modifies the login process, directing the user to third party services. + +To expose the links provided by these add-ons, `plone.restapi` provides an adapter based service registration. +It lets those add-ons know that the REST API can use those services to authenticate users. +This will mostly be used by frontends that need to show the end user the links to those services. + +To achieve that, third party products need to register one or more adapters for the Plone site root object, providing the `plone.restapi.interfaces.IExternalLoginProviders` interface. + +In the adapter, the add-on needs to return the list of external links and some metadata, including the `id`, `title`, and name of the `plugin`. + +An example adapter would be the following, in a file named {file}`adapter.py`: + +```python +from zope.component import adapter +from zope.interface import implementer + +@adapter(IPloneSiteRoot) +@implementer(IExternalLoginProviders) +class MyExternalLinks: + def __init__(self, context): + self.context = context + + def get_providers(self): + return [ + { + "id": "myprovider", + "title": "Provider", + "plugin": "pas.plugins.authomatic", + "url": "https://some.example.com/login-url", + }, + { + "id": "github", + "title": "GitHub", + "plugin": "pas.plugins.authomatic", + "url": "https://some.example.com/login-authomatic/github", + }, + ] +``` + +With the corresponding ZCML stanza, in the corresponding {file}`configure.zcml` file: + +```xml + +``` + +The API request would be as follows: + +```{eval-rst} +.. http:example:: curl httpie python-requests + :request: ../../../src/plone/restapi/tests/http-examples/external_authentication_links.req +``` + +The server will respond with a `Status 200` and the list of external providers: + +```{literalinclude} ../../../src/plone/restapi/tests/http-examples/external_authentication_links.resp +:language: http +``` diff --git a/news/1757.feature b/news/1757.feature new file mode 100644 index 0000000000..c678441b4e --- /dev/null +++ b/news/1757.feature @@ -0,0 +1 @@ +Add a `@login` endpoint to get external login services' links. @erral diff --git a/src/plone/restapi/interfaces.py b/src/plone/restapi/interfaces.py index 5c2aa337e6..9d5c2bcede 100644 --- a/src/plone/restapi/interfaces.py +++ b/src/plone/restapi/interfaces.py @@ -240,3 +240,14 @@ class IBlockVisitor(Interface): def __call__(self, block): """Return an iterable of sub-blocks found inside `block`.""" + + +class ILoginProviders(Interface): + """An interface needed to be implemented by providers that want to be listed + in the @login endpoint + """ + + def get_providers(): + """ + return a list of login providers, with its id, title, plugin and url + """ diff --git a/src/plone/restapi/services/auth/configure.zcml b/src/plone/restapi/services/auth/configure.zcml index dec5304c50..f5604d81f2 100644 --- a/src/plone/restapi/services/auth/configure.zcml +++ b/src/plone/restapi/services/auth/configure.zcml @@ -3,6 +3,13 @@ xmlns:plone="http://namespaces.plone.org/plone" xmlns:zcml="http://namespaces.zope.org/zcml" > +