Expand my Community achievements bar.

Enhance your AEM Assets & Boost Your Development: [AEM Gems | June 19, 2024] Improving the Developer Experience with New APIs and Events
SOLVED

AEM SSO authentication in component level

Avatar

Level 1

We have asset-details page where we show asset details(metadata). we pass the dam asset path in the details page suffix.

The asset details are shown in the asset-details component in asset-details page.

 

we maintain the asset access level in asset metadata property itself like

user-access=public,private

or

user-access=public

or

user-access=private

 

We have following use cases.

1. if anonymous user access the public asset(user-access=public) then the asset details page should render properly

2. if sso logged-in user access the private or public asset(user-access=public,private) then the asset details page should render properly

3. if anonymous user access the private asset(user-access=private) then in the java code has to do saml authentication and land in the same page.

 

Note: In our site some pages we configured saml authentication and it is working fine but we didnt add the asset-details page path in the saml configuration because asset-datails page some time should act as public page.

 

Please  need opinions on use-case #3  and thanks in advance.

 

 

 

1 Accepted Solution

Avatar

Correct answer by
Level 9

Hi @saibul2 ,

To handle the use case where anonymous users trying to access private assets are redirected to SSO (SAML) authentication and then landed back on the same asset details page, you'll need to incorporate custom logic into your AEM component and potentially use a servlet or filter to manage the authentication flow. Here’s a step-by-step guide on how to achieve this:

Step-by-Step Solution:

  1. Component Logic for Asset Access:

    • Modify your asset-details component to check the user-access metadata property and determine if the asset is public or private.
    • Based on the access level and user authentication status, redirect to SSO authentication if needed.
  2. Servlet/Filter for SSO Redirection:

    • Create a servlet or filter that intercepts requests to the asset-details page.
    • If the asset is private and the user is not authenticated, redirect to the SSO login URL.
    • Ensure the user is redirected back to the original asset-details page after successful SSO authentication.

Example Implementation:

1. Component Logic:

Update your asset-details component's Java class to check the asset metadata and user authentication status:

 

import com.day.cq.dam.api.Asset;
import org.apache.sling.api.SlingHttpServletRequest;
import org.apache.sling.api.SlingHttpServletResponse;
import org.apache.sling.api.resource.Resource;
import org.apache.sling.api.servlets.SlingSafeMethodsServlet;
import org.osgi.service.component.annotations.Component;
import org.osgi.service.component.propertytypes.ServiceDescription;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.jcr.RepositoryException;
import javax.servlet.Servlet;
import javax.servlet.ServletException;
import java.io.IOException;

@Component(service = {Servlet.class})
@ServiceDescription("Asset Details Servlet")
public class AssetDetailsServlet extends SlingSafeMethodsServlet {

    private static final Logger log = LoggerFactory.getLogger(AssetDetailsServlet.class);

    @Override
    protected void doGet(SlingHttpServletRequest request, SlingHttpServletResponse response)
            throws ServletException, IOException {

        String assetPath = request.getRequestPathInfo().getSuffix();
        Resource assetResource = request.getResourceResolver().getResource(assetPath);
        if (assetResource != null) {
            Asset asset = assetResource.adaptTo(Asset.class);
            if (asset != null) {
                String userAccess = asset.getMetadataValue("user-access");
                if (userAccess != null) {
                    boolean isUserAuthenticated = request.getUserPrincipal() != null;
                    boolean isPublicAsset = userAccess.contains("public");
                    boolean isPrivateAsset = userAccess.contains("private");

                    if (isPublicAsset || (isPrivateAsset && isUserAuthenticated)) {
                        // Render the asset details page
                        request.getRequestDispatcher("/content/asset-details-page.html").forward(request, response);
                    } else if (isPrivateAsset && !isUserAuthenticated) {
                        // Redirect to SSO login
                        String redirectUrl = "/content/sso/login?resource=" + request.getRequestURI();
                        response.sendRedirect(redirectUrl);
                    } else {
                        response.sendError(SlingHttpServletResponse.SC_FORBIDDEN, "Access denied");
                    }
                }
            } else {
                response.sendError(SlingHttpServletResponse.SC_NOT_FOUND, "Asset not found");
            }
        } else {
            response.sendError(SlingHttpServletResponse.SC_NOT_FOUND, "Resource not found");
        }
    }
}

 

2. SSO Redirection and Return:

Configure your SSO system to handle the resource parameter in the query string so that after successful authentication, the user is redirected back to the original asset details page.

In your SSO login handler, capture the resource parameter and use it to redirect the user post-authentication:

 

// Pseudo-code for SSO login handler
String resource = request.getParameter("resource");
if (resource != null && !resource.isEmpty()) {
    response.sendRedirect(resource);
} else {
    response.sendRedirect("/default-redirect-page");
}

 

3. AEM Filter for Enhanced Control:

You can also create an AEM filter to handle the logic of checking access levels and performing the redirection. This can help you centralize the access control logic.

 

import org.apache.sling.api.SlingHttpServletRequest;
import org.apache.sling.api.SlingHttpServletResponse;
import org.apache.sling.api.resource.Resource;
import org.apache.sling.api.resource.ValueMap;
import org.apache.sling.api.servlets.HttpConstants;
import org.apache.sling.engine.EngineConstants;
import org.osgi.service.component.annotations.Component;
import org.osgi.service.component.propertytypes.ServiceDescription;

import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

@Component(service = Filter.class, property = {
        EngineConstants.SLING_FILTER_SCOPE + "=" + EngineConstants.FILTER_SCOPE_REQUEST,
        "sling.filter.pattern=/content/asset-details.*"
})
@ServiceDescription("Asset Access Control Filter")
public class AssetAccessControlFilter implements Filter {

    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
    }

    @Override
    public void doFilter(javax.servlet.ServletRequest servletRequest, javax.servlet.ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        SlingHttpServletRequest request = (SlingHttpServletRequest) servletRequest;
        SlingHttpServletResponse response = (SlingHttpServletResponse) servletResponse;

        String assetPath = request.getRequestPathInfo().getSuffix();
        Resource assetResource = request.getResourceResolver().getResource(assetPath);
        if (assetResource != null) {
            ValueMap properties = assetResource.getValueMap();
            String userAccess = properties.get("user-access", String.class);

            if (userAccess != null) {
                boolean isUserAuthenticated = request.getUserPrincipal() != null;
                boolean isPublicAsset = userAccess.contains("public");
                boolean isPrivateAsset = userAccess.contains("private");

                if (isPublicAsset || (isPrivateAsset && isUserAuthenticated)) {
                    filterChain.doFilter(servletRequest, servletResponse);
                } else if (isPrivateAsset && !isUserAuthenticated) {
                    String redirectUrl = "/content/sso/login?resource=" + request.getRequestURI();
                    response.sendRedirect(redirectUrl);
                } else {
                    response.sendError(HttpServletResponse.SC_FORBIDDEN, "Access denied");
                }
            } else {
                filterChain.doFilter(servletRequest, servletResponse);
            }
        } else {
            response.sendError(HttpServletResponse.SC_NOT_FOUND, "Resource not found");
        }
    }

    @Override
    public void destroy() {
    }
}

 

  1. Component Logic: Add logic in your asset-details component to check the asset's access level and user authentication status.
  2. Servlet/Filter: Create a servlet or filter to handle redirection to the SSO login page when an unauthenticated user tries to access a private asset.
  3. SSO Configuration: Ensure your SSO system can handle redirection back to the original asset details page after successful authentication.

By implementing these steps, you can ensure that your asset-details page handles public and private asset access appropriately and supports SSO authentication when necessary.

View solution in original post

1 Reply

Avatar

Correct answer by
Level 9

Hi @saibul2 ,

To handle the use case where anonymous users trying to access private assets are redirected to SSO (SAML) authentication and then landed back on the same asset details page, you'll need to incorporate custom logic into your AEM component and potentially use a servlet or filter to manage the authentication flow. Here’s a step-by-step guide on how to achieve this:

Step-by-Step Solution:

  1. Component Logic for Asset Access:

    • Modify your asset-details component to check the user-access metadata property and determine if the asset is public or private.
    • Based on the access level and user authentication status, redirect to SSO authentication if needed.
  2. Servlet/Filter for SSO Redirection:

    • Create a servlet or filter that intercepts requests to the asset-details page.
    • If the asset is private and the user is not authenticated, redirect to the SSO login URL.
    • Ensure the user is redirected back to the original asset-details page after successful SSO authentication.

Example Implementation:

1. Component Logic:

Update your asset-details component's Java class to check the asset metadata and user authentication status:

 

import com.day.cq.dam.api.Asset;
import org.apache.sling.api.SlingHttpServletRequest;
import org.apache.sling.api.SlingHttpServletResponse;
import org.apache.sling.api.resource.Resource;
import org.apache.sling.api.servlets.SlingSafeMethodsServlet;
import org.osgi.service.component.annotations.Component;
import org.osgi.service.component.propertytypes.ServiceDescription;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.jcr.RepositoryException;
import javax.servlet.Servlet;
import javax.servlet.ServletException;
import java.io.IOException;

@Component(service = {Servlet.class})
@ServiceDescription("Asset Details Servlet")
public class AssetDetailsServlet extends SlingSafeMethodsServlet {

    private static final Logger log = LoggerFactory.getLogger(AssetDetailsServlet.class);

    @Override
    protected void doGet(SlingHttpServletRequest request, SlingHttpServletResponse response)
            throws ServletException, IOException {

        String assetPath = request.getRequestPathInfo().getSuffix();
        Resource assetResource = request.getResourceResolver().getResource(assetPath);
        if (assetResource != null) {
            Asset asset = assetResource.adaptTo(Asset.class);
            if (asset != null) {
                String userAccess = asset.getMetadataValue("user-access");
                if (userAccess != null) {
                    boolean isUserAuthenticated = request.getUserPrincipal() != null;
                    boolean isPublicAsset = userAccess.contains("public");
                    boolean isPrivateAsset = userAccess.contains("private");

                    if (isPublicAsset || (isPrivateAsset && isUserAuthenticated)) {
                        // Render the asset details page
                        request.getRequestDispatcher("/content/asset-details-page.html").forward(request, response);
                    } else if (isPrivateAsset && !isUserAuthenticated) {
                        // Redirect to SSO login
                        String redirectUrl = "/content/sso/login?resource=" + request.getRequestURI();
                        response.sendRedirect(redirectUrl);
                    } else {
                        response.sendError(SlingHttpServletResponse.SC_FORBIDDEN, "Access denied");
                    }
                }
            } else {
                response.sendError(SlingHttpServletResponse.SC_NOT_FOUND, "Asset not found");
            }
        } else {
            response.sendError(SlingHttpServletResponse.SC_NOT_FOUND, "Resource not found");
        }
    }
}

 

2. SSO Redirection and Return:

Configure your SSO system to handle the resource parameter in the query string so that after successful authentication, the user is redirected back to the original asset details page.

In your SSO login handler, capture the resource parameter and use it to redirect the user post-authentication:

 

// Pseudo-code for SSO login handler
String resource = request.getParameter("resource");
if (resource != null && !resource.isEmpty()) {
    response.sendRedirect(resource);
} else {
    response.sendRedirect("/default-redirect-page");
}

 

3. AEM Filter for Enhanced Control:

You can also create an AEM filter to handle the logic of checking access levels and performing the redirection. This can help you centralize the access control logic.

 

import org.apache.sling.api.SlingHttpServletRequest;
import org.apache.sling.api.SlingHttpServletResponse;
import org.apache.sling.api.resource.Resource;
import org.apache.sling.api.resource.ValueMap;
import org.apache.sling.api.servlets.HttpConstants;
import org.apache.sling.engine.EngineConstants;
import org.osgi.service.component.annotations.Component;
import org.osgi.service.component.propertytypes.ServiceDescription;

import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

@Component(service = Filter.class, property = {
        EngineConstants.SLING_FILTER_SCOPE + "=" + EngineConstants.FILTER_SCOPE_REQUEST,
        "sling.filter.pattern=/content/asset-details.*"
})
@ServiceDescription("Asset Access Control Filter")
public class AssetAccessControlFilter implements Filter {

    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
    }

    @Override
    public void doFilter(javax.servlet.ServletRequest servletRequest, javax.servlet.ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        SlingHttpServletRequest request = (SlingHttpServletRequest) servletRequest;
        SlingHttpServletResponse response = (SlingHttpServletResponse) servletResponse;

        String assetPath = request.getRequestPathInfo().getSuffix();
        Resource assetResource = request.getResourceResolver().getResource(assetPath);
        if (assetResource != null) {
            ValueMap properties = assetResource.getValueMap();
            String userAccess = properties.get("user-access", String.class);

            if (userAccess != null) {
                boolean isUserAuthenticated = request.getUserPrincipal() != null;
                boolean isPublicAsset = userAccess.contains("public");
                boolean isPrivateAsset = userAccess.contains("private");

                if (isPublicAsset || (isPrivateAsset && isUserAuthenticated)) {
                    filterChain.doFilter(servletRequest, servletResponse);
                } else if (isPrivateAsset && !isUserAuthenticated) {
                    String redirectUrl = "/content/sso/login?resource=" + request.getRequestURI();
                    response.sendRedirect(redirectUrl);
                } else {
                    response.sendError(HttpServletResponse.SC_FORBIDDEN, "Access denied");
                }
            } else {
                filterChain.doFilter(servletRequest, servletResponse);
            }
        } else {
            response.sendError(HttpServletResponse.SC_NOT_FOUND, "Resource not found");
        }
    }

    @Override
    public void destroy() {
    }
}

 

  1. Component Logic: Add logic in your asset-details component to check the asset's access level and user authentication status.
  2. Servlet/Filter: Create a servlet or filter to handle redirection to the SSO login page when an unauthenticated user tries to access a private asset.
  3. SSO Configuration: Ensure your SSO system can handle redirection back to the original asset details page after successful authentication.

By implementing these steps, you can ensure that your asset-details page handles public and private asset access appropriately and supports SSO authentication when necessary.