0

I'm trying to implement a logout servlet in cq5, where I need to logout my users from a cas server and cq5. The problem is that I need the servlet to both logout from cq5 and then redirect to the cas logout page, but since I'm using a response to do both these things I get an IllegalStateException.

Any idea on how to do this?

This is my servlet code:

import com.stuff.etc.*;

@Component( metatype = false)
@SlingServlet(
        methods = {"GET"},
        generateComponent = false        
)
@Service
public class MyLogoutServlet extends SlingAllMethodsServlet {   

    @Reference(cardinality = ReferenceCardinality.OPTIONAL_UNARY, policy = ReferencePolicy.DYNAMIC)
    private Authenticator authenticator;

    public static final String PAR_USER = "username";

    @Property(name = "sling.servlet.paths")
    public static final String SERVLET_PATH = "/system/mysite/logout";

    @Property(name = "sling.auth.requirements", propertyPrivate = true)
    //@SuppressWarnings("unused")
    private static final String[] AUTH_REQUIREMENT = { "-" + SERVLET_PATH };

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

    public static final String TOKEN_COOKIE_ID = "mysite_auth";

    private static final String LOGOUT_RESOURCE = "https://casurl.com/logout";

    @Reference
    private CryptoSupport cryptoSupport;

    @Reference
    private SlingSettingsService settingsService;

    @Override
    protected void doGet(SlingHttpServletRequest request,   SlingHttpServletResponse response) throws ServletException, IOException {
        String username = request.getParameter(PAR_USER);                       

        final Authenticator authenticator = this.authenticator;
        log.info(String.valueOf(authenticator==null));

        if(username != null) {
            if(log.isDebugEnabled()) {
                log.debug("Request to logout user: " + username);
            }
            request.removeAttribute(WSCAuthToken.TOKEN_ATTR_USER);
            WSCAuthToken token = getAuthToken(request, cryptoSupport);

            //if(token != null && token.isDebugMode()) {
            if(token != null) {
                token.setUser(null);
                token.resetAttributes();
                saveAuthCookie(request, response, cryptoSupport, token);

                CookieStoreUtil.resetStoreCookie(request, response, settingsService);               
                TokenCookie.setCookie(response, TOKEN_COOKIE_ID, "", -1, "/", null, false, request.isSecure());

                if (authenticator != null) {
                    try {
                        log.info("SIAMO QUI");
                        log.info("ANDIAMO QUI: "+request.getContextPath());
                        AbstractAuthenticationHandler.setLoginResourceAttribute(request, request.getContextPath());
                        authenticator.logout(request, response);
                    } catch (IllegalStateException ise) {
                        log.error("service: Response already committed, cannot logout");
                        return;
                    }
                } else {
                    log.error("service: Authenticator service missing, cannot logout");
                }

            } else {
                response.sendError(HttpServletResponse.SC_UNAUTHORIZED);        
            }                           
        }   else {  
            response.sendError(HttpServletResponse.SC_BAD_REQUEST, "Username non specificato");     
        }
        response.sendRedirect(LOGOUT_RESOURCE);
        //response.setStatus(HttpServletResponse.SC_NO_CONTENT);
    }   

    public static WSCAuthToken getAuthToken(HttpServletRequest request, CryptoSupport cryptoSupport) {
        WSCAuthToken token = null;

        Object tokenAttr = request.getAttribute(TOKEN_COOKIE_ID);
        if ((tokenAttr instanceof WSCAuthToken)) {          
            return (WSCAuthToken)tokenAttr;
        }

        String cookie = TokenCookie.getCookie(request, TOKEN_COOKIE_ID);                            

        if (cookie != null) {
            String value;
            try {
                value = cryptoSupport.unprotect(cookie);
                token = WSCAuthToken.fromJSON(value);
            } catch (CryptoException e) {
                log.error("CryptoException getting token: " + e.getMessage());
            }           
        }
        return token;
    } 

    public static void saveAuthCookie(HttpServletRequest request, HttpServletResponse response, 
            CryptoSupport cryptoSupport, WSCAuthToken token) {

        try {           
            request.setAttribute(token.getCk(), token);
            String value = cryptoSupport.protect(token.toJSON());           
            TokenCookie.setCookie(response, TOKEN_COOKIE_ID, "\"" + value + "\"", -1, "/", null, true, request.isSecure());         
        } catch (CryptoException e) {
            log.error("CryptoException saving cookie", e);
        } catch (IOException e) {
            log.error("IOException saving cookie", e);
        }   
    }
}

The log for the error: 02.08.2013 11:03:23.966 *ERROR* [127.0.0.1 [1375434203945] GET /system/sorgeniabpp/logout HTTP/1.1] org.apache.sling.engine.impl.SlingRequestProcessorImpl service: Uncaught Throwable java.lang.IllegalStateException: response already committed

Also another problem is that I don't even get to logout from CQ5. I've tried to merge my servlet with the code implemented on org.apache.sling.auth.core.impl.LogoutServlet but with no results.

tony danza
  • 306
  • 7
  • 22

2 Answers2

0

Try to add return statement after the redirection,So that it stops adding further content to the response.

  response.sendRedirect(LOGOUT_RESOURCE);
  return; 

The server has already finished writing the response header and is writing the body of the content, and which point you are trying to write more to the header - of course it cant rewind.

Suresh Atta
  • 120,458
  • 37
  • 198
  • 307
0

you need to add return statement even after sendError(As already @suresh atta told you that you need to add return statement after redirection).
Accroding to HttpServletResponse#sendRedirect and HttpServletResponse#sendError

If the response has already been committed, this method throws an IllegalStateException.After using this method, the response should be considered to be committed and should not be written to.

So return statement after sendError also.

 response.sendError(HttpServletResponse.SC_UNAUTHORIZED); 
 return;

and

 response.sendError(HttpServletResponse.SC_BAD_REQUEST, "Username non specificato");
 return;

with this

 response.sendRedirect(LOGOUT_RESOURCE);
 return;

For more details about why you need to add return statement after redirect or sendError

Community
  • 1
  • 1
Prabhaker A
  • 8,317
  • 1
  • 18
  • 24