Shibboleth and Volto?

Can i use Shibboleth with Plone 6 Volto? For a Classic UI Installation i know what i should do, but if i decide me for a Volto Frontend, there are some Problems?

For a Classic UI Installation i know what i should do,

That's interesting to know, how would you add Shibboleth support to Classic UI? If you provide that information, maybe other community members who know more about Volto can assist you with providing information on how to amend / support also the Volto Frontend.

I use the AutoUserMakerPASPlugin. The saml2 part happen in an apache plugin :wink:

1 Like

We use Shibboleth and Volto with following setup:

  • Backend: pas.plugins.header to use request headers set by Shibboleth to do the authentication
  • nginx*/shibd:
    • Configure /login to enforce Shibboleth login
    • Configure /++api++/@login-renew to provide Shibboleth headers
  • Frontend (Volto): Custom login component that performs loginRenew action to retrieve and store login token in the frontend state

So the login flow is:

  1. User visits secured page
  2. Is redirect to /login
  3. Is forced to do Shibboleth login
  4. Redirected to our custom login component ...
  5. which calls @login-renew, and sets retrieved auth token
  6. and redirects to requested secured page

Changes in Volto:

config.js
config.addonRoutes.push(
    /* replace original login by our Shibboleth component */
    {
      path: ['/login', '/**/login'],
      component: Shibboleth,
    },
    /* but keep local login available */
    {
      path: '**/local-login',
      component: Login,
    },
  );
Shibboleth.jsx
import { useEffect } from 'react';
import { FormattedMessage } from 'react-intl';
import { useDispatch, useSelector } from 'react-redux';
import { Container, Dimmer, Loader } from 'semantic-ui-react';
import { loginRenew } from '@plone/volto/actions';
import { ContentPlaceholder } from '@package/components';

/* This component calls @login-renew endpoint.
   When user is authenticated via Shibboleth and
   backend is configured properly, client receives
   a login token and user will be logged in.
*/
const Shibboleth = () => {
  const token = useSelector((state) => state.userSession?.token || false);
  if (token && __CLIENT__)
    window.location.href = window.location.href.replace('/login', '');

  const dispatch = useDispatch();
  useEffect(() => {
    if (__CLIENT__) dispatch(loginRenew());
  }, [dispatch]);

  return (
    <Container className="view-wrapper">
      <Dimmer.Dimmable as={Container} dimmed={true}>
        <ContentPlaceholder />
        <Dimmer active={true} className="embedded">
          <Loader size="large" inline="centered" active>
            <FormattedMessage
              id="Login is performed"
              defaultMessage="Login is performed"
            />
          </Loader>
        </Dimmer>
      </Dimmer.Dimmable>
    </Container>
  );
};

export default Shibboleth;

* dont do it with nginx if you can avoid it :wink: