Avoid configuring an alternative identity provider without first testing it. If things don’t work out with the Magnolia SSO module, you should be able to dump, replace, or rebuild the repository.
The ability to delete repository data on development instances is considered best practice.
If you are unable to restore a locked Magnolia instance, consider one of the following options:
Use a mock server
The best way to get access to Magnolia AdminCentral is to use a fake server that lets you access Magnolia with any username/password combination and adds the superuser role to that account.
There are instructions for using a dummy server in the Magnolia documentation.
The example on the documentation page may need to be adjusted to match your environment and the latest version of the Magnolia SSO module you’re using.
Set up a simulation environment
I found that the following combination worked for me (I used the Docker image).
Light module configuration decoration file for my development instance running under http://localhost:8080/magnoliaAuthor:
path: /.magnolia/admincentral
callbackUrl: http://localhost:8080/magnoliaAuthor/.auth
postLogoutRedirectUri: http://localhost:8080/magnoliaAuthor/.magnolia/admincentral
authorizationGenerators:
- name: fixedRoleAuthorization
fixed:
targetRoles:
- superuser
clients:
oidc.id: mock-client-id
oidc.secret: mock-client-secret
oidc.scope: openid profile email
oidc.discoveryUri: http://localhost:9090/.well-known/openid-configuration
oidc.preferredJwsAlgorithm: RS256
oidc.authorizationGenerators: fixedRoleAuthorization
userFieldMappings:
name: preferred_username
removeEmailDomainFromUserName: true
removeSpecialCharactersFromUserName: false
fullName: name
email: email
language: locale
Docker command: Mock server running on port 9090:
docker run \
--env PORT=9090 \
--env CLIENT_ID=mock-client-id \
--env CLIENT_SECRET=mock-client-secret \
--env CLIENT_REDIRECT_URI=http://localhost:8080/magnoliaAuthor/.auth \
--env CLIENT_LOGOUT_REDIRECT_URI=http://localhost:8080/magnoliaAuthor/.magnolia/admincentral \
-p 9090:9090 \
mgnl/mock-oidc-user-server:latest
Access Magnolia
If the login process works, the mock server will handle it.
Remove SSO configuration
This approach requires you to be capable of altering and redeploying the Magnolia WAR bundle.
Before proceeding, please read the documentation.
- Make sure you have everything you need and back up your repository before making any changes.
- Rename the file {your-webapp}\src\main\webapp\WEB-INF\config\jaas.config (e.g., “jaas.config.save”).
- Remove or comment out the Magnolia SSO feature in Maven.
- The Magnolia SSO light module configuration can be removed.
- Customize or deploy a web.xml according to the Rescue App documentation.
- Stop Magnolia, build and deploy the customized bundle, and run it.
The Rescue App’s console should now appear in your browser window.
In the console, please execute the following lines without any comments.
session = ctx.getJCRSession('config')
// delete client callback
root = session.getNode('/server/filters/securityCallback/clientCallbacks')
root.getNode('magnolia-sso').remove()
// set default login filter
root = session.getNode('/server/filters/login')
root.setProperty('class', 'info.magnolia.cms.security.auth.login.LoginFilter')
// set default logout filter
root = session.getNode('/server/filters/logout')
root.setProperty('class', 'info.magnolia.cms.security.LogoutFilter')
// remove module magnolia-sso
root = session.getNode('/modules')
root.getNode('magnolia-sso').remove()
// save your changes!
session.save()
Remember to save your changes when you finish!
Stopping your Magnolia instance and configuring the web.xml file will ensure that the Magnolia filter chain is not ignored after tweaking the JCR configuration.
Build and deploy the Magnolia bundle, then launch AdminCentral.
You should be able to log into one of your local Magnolia accounts if everything goes as expected.
Note that by following the steps above, we did not completely remove all the settings previously made by the Magnolia SSO module. However, since we have regained visual access to AdminCentral, you can use the UI to remove obsolete configuration entries. Checking the module’s version handler can help you find out what’s changed, You will find the code in Magnolia Git. Check to see if the version matches the one you’re using for your project.
Introducing a temporary login filter class
If you can manipulate the WAR bundle on the server side (either in the source or as a hotfix under WEB-INF/classes), you can provide a temporary login filter class to replace the one provided by the Magnolia SSO module.
Within a module that depends on the Magnolia SSO module (defined in your Magnolia module descriptor under META-INF/magnolia), create a class with the exact package and name:
info.magnolia.sso.SsoLoginFilter
The login filter class will be replaced with your temporary version since the module depends on SSO. Setting dependencies in the Maven POM doesn’t guarantee the right module order.
Create code that handles logins, for example:
package info.magnolia.sso;
import info.magnolia.cms.filters.AbstractMgnlFilter;
import info.magnolia.cms.filters.MgnlFilterChain;
import info.magnolia.cms.security.SecuritySupport;
import info.magnolia.cms.security.SecuritySupportBase;
import info.magnolia.cms.security.UserManager;
import info.magnolia.cms.security.auth.callback.CredentialsCallbackHandler;
import info.magnolia.cms.security.auth.callback.PlainTextCallbackHandler;
import info.magnolia.cms.security.auth.login.LoginResult;
import info.magnolia.context.Context;
import info.magnolia.context.MgnlContext;
import info.magnolia.context.UserContext;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.Optional;
import static info.magnolia.cms.security.LogoutFilter.PARAMETER_LOGOUT;
public class SsoLoginFilter extends AbstractMgnlFilter {
private static final Logger log = LoggerFactory.getLogger(SsoLoginFilter.class);
public static final String DEFAULT_USER_ID = "superuser";
public static final String DEFAULT_USER_PWD = "superuser";+
public static final String PARAMETER_USER_ID = "mgnlUserId";
public static final String PARAMETER_PSWD = "mgnlUserPSWD";
@Override
public void doFilter(HttpServletRequest request, HttpServletResponse response, FilterChain chain) throws IOException, ServletException {
if (Optional.ofNullable(request.getParameter(PARAMETER_LOGOUT)).isPresent()) {
log.info("Logout parameter has been provided.");
Context ctx = MgnlContext.getInstance();
if (ctx instanceof UserContext) {
((UserContext) ctx).logout();
}
if (request.getSession(false) != null) {
request.getSession().invalidate();
}
if (chain instanceof MgnlFilterChain) {
((MgnlFilterChain) chain).reset();
}
return;
} else {
if (UserManager.ANONYMOUS_USER.equals(MgnlContext.getUser().getName())) {
String userId = StringUtils.isNotBlank(request.getParameter(PARAMETER_USER_ID)) ? request.getParameter(PARAMETER_USER_ID) : DEFAULT_USER_ID;
log.info("Handle login for {}", userId);
String pswd = StringUtils.isNotBlank(request.getParameter(PARAMETER_PSWD)) ? request.getParameter(PARAMETER_PSWD) : DEFAULT_USER_PWD;
CredentialsCallbackHandler callbackHandler = new PlainTextCallbackHandler(userId, pswd.toCharArray(), "");
LoginResult result = SecuritySupport.Factory.getInstance().authenticate(callbackHandler, SecuritySupportBase.DEFAULT_JAAS_LOGIN_CHAIN);
log.info("Login result: " + result.getStatus());
if (result.getStatus() == LoginResult.STATUS_SUCCEEDED) {
log.info("Sucessfully logged in the user.");
log.info("Subject: " + result.getSubject());
if (request.getSession(false) != null) {
request.getSession().invalidate();
}
MgnlContext.login(result.getSubject());
} else {
log.info("The login was not successful.");
}
}
}
chain.doFilter(request, response);
}
}
The example works this way:
- You can specify the login parameters (mgnlUserId and mgnlUserPSWD), such as http://localhost:8080/magnoliaAuthor?mgnlUserId=superuser&mgnlUserU.
- If you don’t set the parameters, the default values will be used.
Naturally, any working code logic can be used.
Please look at the following:
- The user must be located within the Magnolia JCR.
- The user’s name and password must match.
- After logging in, the user must be enabled and have the necessary rights.
Deploy the class as hotfix
If you are unable to create an entirely new WAR package, you can provide the compiled class as a hotfix (under WEB-INF/classes). Please make sure the package structure is maintained. Depending on your setup and infrastructure, this may only require a server restart.
Please remove this temporary hack once you have finished working on the Magnolia instance.