Empresas
Empleos
  • Sobre nosotros
  • Soluciones
    • Publicación de vacantes
      Publica tu vacante y recibe candidatos calificados en 48h.
    • Evaluación de candidatos
      500+ pruebas técnicas y psicológicas, más anti-fraude.
    • Headhunting
      Búsqueda ejecutiva a la medida de principio a fin.
    • Nómina + EOR
      Dispersión de nómina y EOR en más de 15 países de LATAM.
  • Precios
  • Empleos

0

187
Vistas
How to redirect app in Struts 2 with Azure SSO

I am wanting to implement a SSO with Azure to an application that is built with Struts 2, I have already implemented the filter to make me the login from the microsoft page.

enter image description here

however the redirection issue when everything is correct is not quite clear to me as I am not very good with Struts as when you originally log into the app it redirects to a URL like this localhost:8080/Portal/login/loginAction_validateUser.action.

this is the original login class of the application

public class ActionLogin extends ActionSupport implements ServletRequestAware {

    private static Logger logger = LogManager.getLogger(ActionLogin.class);

    private HttpServletRequest request;

    private UtilHttp uhttp = new UtilHttp();

    private UtilFiles ufiles = new UtilFiles();

    private User user;

    private Person person;

    private int invalidateSession;

   
    public void setServletRequest(HttpServletRequest request) {
        this.request = request;
    }

  
    public String validateUser() {
        try {

            HttpSession session = request.getSession();
            uhttp.cleanSession(request);
            LoginBusiness business = new LoginBusiness();
            String page = "menu";
            boolean loadMenu = true;

            if (invalidateSession == 1) {
               
                new LoginBusiness().createDifferentSession(session, user.getLogin());
                invalidateSession = 0;
            } 

            user = business.validateUser(user.getLogin(), user.getPassword(), user.getIdProfile());
            if (business.isUserLocked(user.getIdUser())) {
                 
                    addActionError(PortalAdministracionErrorCode.E0400.getMessage());
                return "blockedAccount";
                }

            if (user.isValidAuth()) {
                logger.info("user.isValidAuth()");

                if (user.isChangePassword()) {
                 
                    loadMenu = false;
                    page = "change";
                }
                
                if (business.isPasswordExpired(user.getIdUser())) {
                   
                    addActionError(getText(PortalAdministracionErrorCode.E0401.getMessage()));
                    loadMenu = false;
                    return "passwordexpired";
                }

     
                session = request.getSession(true);
                session.setAttribute(Constants.SESSION_USER, user);

            } else {
               
                addActionError(getText("label.error.login.password"));
                user.setAuthType("1");
                page = "login";
            }

            return page;

        } catch (Exception e) {
            addActionError(e.getMessage());
            return "login";
        }
    }

 

    public String logOut() {
        HttpSession session = request.getSession(false);
        if (session != null) {

            try {
                logger.info("Realiza un logOut el usuario ");
                uhttp.cleanSession(request);
                return "logout";
                //session.invalidate();
            } catch (Exception ex) {
                logger.error(ex);
                return "logout";
            }
        }
        return "logout";
    }

    public String invalidateSession() {
        invalidateSession = 0;
        return "login";
    }

    public User getUser() {
        return user;
    }

    public void setUser(User user) {
        this.user = user;
    }

    public Person getPerson() {
        return person;
    }

    public void setPerson(Person person) {
        this.person = person;
    }

    public int getInvalidateSession() {
        return invalidateSession;
    }

    public void setInvalidateSession(int invalidateSession) {
        this.invalidateSession = invalidateSession;
    }
}

this is the XML that is configured with struts, when the login is ok it redirects to the JSP called entrada.jsp but in the url it does not change when it does this if it does not put the action of the login that was made, any idea how to adapt it?

my login.xml

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE struts PUBLIC
    "-//Apache Software Foundation//DTD Struts Configuration 2.5//EN"
    "http://struts.apache.org/dtds/struts-2.5.dtd">
    
<struts>
    <package name="login" namespace="/login" extends="struts-default,json-default">

        <interceptors>
            <interceptor-stack name="defaultSecurityStack">
                <interceptor-ref name="tokenSession">
                    <param name="excludeMethods">*</param>
                </interceptor-ref>
                <interceptor-ref name="defaultStack" />
            </interceptor-stack>
        </interceptors>
        
        <default-interceptor-ref name="defaultSecurityStack" />
        
        <global-results>
            <result name="error">/jsp/common/errorDetail.jsp</result>
            <result name="invalid.token">/jsp/Login.jsp</result>
        </global-results>  
        
        <action name="loginAction_*" method="{1}" class="action.ActionLogin">           
            <result name="login">/jsp/Login.jsp</result>
            <result name="menu">/jsp/menu/Entrada.jsp</result>
             
            <result name="platformAdmon">/jsp/profile/AddPlatformAdmon.jsp</result>
            <result name="change">/jsp/menu/ChangePassword.jsp</result>
            <result name="passwordexpired">/jsp/login/account/password-expired.jsp</result>
            <result name="success">/jsp/menu/ResultOperation.jsp</result>
           
            <result name="blockedAccount">/jsp/login/account/blocked.jsp</result>
            <result name="logout">/jsp/logout.jsp</result>
            <interceptor-ref name="defaultSecurityStack">
                <param name="tokenSession.excludeMethods">validatePlatformAdmin,logOut,editPassword</param>
            </interceptor-ref>
            <allowed-methods>toPageLogin, addPlatformAdmon, authType, changePassword, editPassword, logOut, showMenu, validatePlatformAdmin, validateUser</allowed-methods>
        </action>
        
        <action name="account_*" method="{1}" class="com.seguridata.rne.administracion.portal.action.LoginAccountAction">
            <result name="login">/jsp/Login.jsp</result>
            <result name="blocked">/jsp/login/account/blocked.jsp</result>
            <result name="resultblocked">/jsp/login/account/blocked-response.jsp</result>
            <result name="unlock">/jsp/login/account/unlock.jsp</result>
            <result name="resultunlock">/jsp/login/account/unlock-response.jsp</result>
            <result name="passwordexpired">/jsp/login/account/password-expired.jsp</result>
            <result name="passwordexpired_success">/jsp/login/account/password-expired-success.jsp</result>
            <interceptor-ref name="defaultSecurityStack">
                <param name="tokenSession.excludeMethods">*</param>
            </interceptor-ref>
            <allowed-methods>unlock, unlockRequest, updatePasswordExpired, validateUnlockRequest</allowed-methods>
        </action>
    </package>    
</struts>

this is my filter code for the SSO redirection I don't really see the issue here but in the configuration in Azure

public class BasicFilter implements Filter {

    public static final String STATES = "states";
    public static final String STATE = "state";
    public static final Integer STATE_TTL = 3600;
    public static final String FAILED_TO_VALIDATE_MESSAGE = "Failed to validate data received from Authorization service - ";
    private String clientId = "";
    private String clientSecret = "";
    private String tenant = "";
    private String authority;

    public void destroy() {

    }

    public void doFilter(ServletRequest request, ServletResponse response,
                         FilterChain chain) throws IOException, ServletException {
       
         HttpServletResponse httpResponse = (HttpServletResponse) response;
         if (request instanceof HttpServletRequest) {
           
            HttpServletRequest httpRequest = (HttpServletRequest) request;
            
            try {
                String currentUri = httpRequest.getRequestURL().toString();
                String queryStr = httpRequest.getQueryString();
                String fullUrl = currentUri + (queryStr != null ? "?" + queryStr : "");

                // check if user has a AuthData in the session
                if (!AuthHelper.isAuthenticated(httpRequest)) {
                    if (AuthHelper.containsAuthenticationData(httpRequest)) {
                        processAuthenticationData(httpRequest, currentUri, fullUrl);
                    } else {
                        // not authenticated
                        sendAuthRedirect(httpRequest, httpResponse);
                        return;
                    }
                }
                if (isAuthDataExpired(httpRequest)) {
                    updateAuthDataUsingRefreshToken(httpRequest);
                }
            } catch (AuthenticationException authException) {
                // something went wrong (like expiration or revocation of token)
                // we should invalidate AuthData stored in session and redirect to Authorization server
                removePrincipalFromSession(httpRequest);
                sendAuthRedirect(httpRequest, httpResponse);
                return;
            } catch (Throwable exc) {
                httpResponse.setStatus(500);
                request.setAttribute("error", exc.getMessage());
                request.getRequestDispatcher("/error.jsp").forward(request, response);
            }
        }
        
     
        chain.doFilter(request, response);
                  
    }

    private boolean isAuthDataExpired(HttpServletRequest httpRequest) {
        AuthenticationResult authData = AuthHelper.getAuthSessionObject(httpRequest);
        return authData.getExpiresOnDate().before(new Date()) ? true : false;
    }

    private void updateAuthDataUsingRefreshToken(HttpServletRequest httpRequest) throws Throwable {
        AuthenticationResult authData =
                getAccessTokenFromRefreshToken(AuthHelper.getAuthSessionObject(httpRequest).getRefreshToken());
        setSessionPrincipal(httpRequest, authData);
    }

    private void processAuthenticationData(HttpServletRequest httpRequest, String currentUri, String fullUrl)
            throws Throwable {
            HttpSession session = httpRequest.getSession(false);
        HashMap<String, String> params = new HashMap<>();
        for (String key : httpRequest.getParameterMap().keySet()) {
            params.put(key, httpRequest.getParameterMap().get(key)[0]);
        }
        // validate that state in response equals to state in request
        StateData stateData = validateState(httpRequest.getSession(), params.get(STATE));

        AuthenticationResponse authResponse = AuthenticationResponseParser.parse(new URI(fullUrl), params);
        if (AuthHelper.isAuthenticationSuccessful(authResponse)) {
            AuthenticationSuccessResponse oidcResponse = (AuthenticationSuccessResponse) authResponse;
            // validate that OIDC Auth Response matches Code Flow (contains only requested artifacts)
            validateAuthRespMatchesCodeFlow(oidcResponse);

            AuthenticationResult authData =
                    getAccessToken(oidcResponse.getAuthorizationCode(), currentUri);
            // validate nonce to prevent reply attacks (code maybe substituted to one with broader access)
            validateNonce(stateData, getClaimValueFromIdToken(authData.getIdToken(), "nonce"));

            setSessionPrincipal(httpRequest, authData);
        } else {
            AuthenticationErrorResponse oidcResponse = (AuthenticationErrorResponse) authResponse;
            throw new Exception(String.format("Request for auth code failed: %s - %s",
                    oidcResponse.getErrorObject().getCode(),
                    oidcResponse.getErrorObject().getDescription()));
        }
    }

    private void validateNonce(StateData stateData, String nonce) throws Exception {
        if (StringUtils.isEmpty(nonce) || !nonce.equals(stateData.getNonce())) {
            throw new Exception(FAILED_TO_VALIDATE_MESSAGE + "could not validate nonce");
        }
    }

    private String getClaimValueFromIdToken(String idToken, String claimKey) throws ParseException {
        return (String) JWTParser.parse(idToken).getJWTClaimsSet().getClaim(claimKey);
    }

    private void sendAuthRedirect(HttpServletRequest httpRequest, HttpServletResponse httpResponse) throws IOException {
        httpResponse.setStatus(302);

        // use state parameter to validate response from Authorization server
        String state = UUID.randomUUID().toString();

        // use nonce parameter to validate idToken
        String nonce = UUID.randomUUID().toString();

        storeStateInSession(httpRequest.getSession(), state, nonce);

        String currentUri = httpRequest.getRequestURL().toString();
        httpResponse.sendRedirect(getRedirectUrl(currentUri, state, nonce));
    }

    /**
     * make sure that state is stored in the session,
     * delete it from session - should be used only once
     *
     * @param session
     * @param state
     * @throws Exception
     */
    private StateData validateState(HttpSession session, String state) throws Exception {
          
        if (StringUtils.isNotEmpty(state)) {
            StateData stateDataInSession = removeStateFromSession(session, state);
            if (stateDataInSession != null) {
                return stateDataInSession;
            }
        }
        throw new Exception(FAILED_TO_VALIDATE_MESSAGE + "could not validate state");
    }

    private void validateAuthRespMatchesCodeFlow(AuthenticationSuccessResponse oidcResponse) throws Exception {
        if (oidcResponse.getIDToken() != null || oidcResponse.getAccessToken() != null ||
                oidcResponse.getAuthorizationCode() == null) {
            throw new Exception(FAILED_TO_VALIDATE_MESSAGE + "unexpected set of artifacts received");
        }
    }

    @SuppressWarnings("unchecked")
    private StateData removeStateFromSession(HttpSession session, String state) {
           
        Map<String, StateData> states = (Map<String, StateData>) session.getAttribute(STATES);
        if (states != null) {
            eliminateExpiredStates(states);
            StateData stateData = states.get(state);
            if (stateData != null) {
                states.remove(state);
                return stateData;
            }
        }
        return null;
    }

    @SuppressWarnings("unchecked")
    private void storeStateInSession(HttpSession session, String state, String nonce) {
        
        if (session.getAttribute(STATES) == null) {
            session.setAttribute(STATES, new HashMap<String, StateData>());
        }
        ((Map<String, StateData>) session.getAttribute(STATES)).put(state, new StateData(nonce, new Date()));
    }

    private void eliminateExpiredStates(Map<String, StateData> map) {
        Iterator<Map.Entry<String, StateData>> it = map.entrySet().iterator();

        Date currTime = new Date();
        while (it.hasNext()) {
            Map.Entry<String, StateData> entry = it.next();
            long diffInSeconds = TimeUnit.MILLISECONDS.
                    toSeconds(currTime.getTime() - entry.getValue().getExpirationDate().getTime());

            if (diffInSeconds > STATE_TTL) {
                it.remove();
            }
        }
    }

    private AuthenticationResult getAccessTokenFromRefreshToken(
            String refreshToken) throws Throwable {
        AuthenticationContext context;
        AuthenticationResult result = null;
        ExecutorService service = null;
        try {
            service = Executors.newFixedThreadPool(1);
            context = new AuthenticationContext(authority + tenant + "/", true,
                    service);
            Future<AuthenticationResult> future = context
                    .acquireTokenByRefreshToken(refreshToken, new ClientCredential(clientId, clientSecret), null, null);
            result = future.get();
        } catch (ExecutionException e) {
            throw e.getCause();
        } finally {
            service.shutdown();
        }

        if (result == null) {
            throw new ServiceUnavailableException("authentication result was null");
        }
        return result;
    }

    private AuthenticationResult getAccessToken(
            AuthorizationCode authorizationCode, String currentUri)
            throws Throwable {
        String authCode = authorizationCode.getValue();
        ClientCredential credential = new ClientCredential(clientId,
                clientSecret);
        AuthenticationContext context;
        AuthenticationResult result = null;
        ExecutorService service = null;
        try {
            service = Executors.newFixedThreadPool(1);
            context = new AuthenticationContext(authority + tenant + "/", true,
                    service);
            Future<AuthenticationResult> future = context
                    .acquireTokenByAuthorizationCode(authCode, new URI(
                            currentUri), credential, null);
            result = future.get();
        } catch (ExecutionException e) {
            throw e.getCause();
        } finally {
            service.shutdown();
        }

        if (result == null) {
            throw new ServiceUnavailableException("authentication result was null");
        }
        return result;
    }

    private void setSessionPrincipal(HttpServletRequest httpRequest,
                                     AuthenticationResult result) {
        httpRequest.getSession().setAttribute(AuthHelper.PRINCIPAL_SESSION_NAME, result);
    }

    private void removePrincipalFromSession(HttpServletRequest httpRequest) {
        httpRequest.getSession().removeAttribute(AuthHelper.PRINCIPAL_SESSION_NAME);
    }

    private String getRedirectUrl(String currentUri, String state, String nonce)
            throws UnsupportedEncodingException {
        String redirectUrl = authority
                + this.tenant
                + "/oauth2/authorize?response_type=code&scope=directory.read.all&response_mode=form_post&redirect_uri="
                + URLEncoder.encode(currentUri, "UTF-8") + "&client_id="
                + clientId + "&resource=https%3a%2f%2fgraph.microsoft.com"
                + "&state=" + state
                + "&nonce=" + nonce;

        return redirectUrl;
    }

    public void init(FilterConfig config) throws ServletException {
        clientId = config.getInitParameter("client_id");
        authority = config.getServletContext().getInitParameter("authority");
        tenant = config.getServletContext().getInitParameter("tenant");
        clientSecret = config.getInitParameter("secret_key");
    }

    private class StateData {
        private String nonce;
        private Date expirationDate;

        public StateData(String nonce, Date expirationDate) {
            this.nonce = nonce;
            this.expirationDate = expirationDate;
        }

        public String getNonce() {
            return nonce;
        }

        public Date getExpirationDate() {
            return expirationDate;
        }
    }
}

my web.xml

<?xml version="1.0" encoding="UTF-8"?>
<web-app version="2.5" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd">
   
    <filter>
        <filter-name>struts-prepare</filter-name>
        <filter-class>org.apache.struts2.dispatcher.filter.StrutsPrepareFilter</filter-class>
    </filter>
    <filter>
        <filter-name>sitemesh</filter-name>
        <filter-class>com.opensymphony.module.sitemesh.filter.PageFilter</filter-class>
    </filter>
    <filter>
        <filter-name>struts-execute</filter-name>
        <filter-class>org.apache.struts2.dispatcher.filter.StrutsExecuteFilter</filter-class>
    </filter>
    <filter>
        <filter-name>struts2</filter-name>
        <filter-class>org.apache.struts2.dispatcher.filter.StrutsPrepareAndExecuteFilter</filter-class>
    </filter>

    <filter-mapping>
        <filter-name>struts-prepare</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>
    <filter-mapping>
        <filter-name>sitemesh</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>
    <filter-mapping>
        <filter-name>struts2</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>
    <filter-mapping>
        <filter-name>struts-execute</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>
        
    <jsp-config>
        <taglib>
            <taglib-uri>/struts-tags</taglib-uri>
            <taglib-location>/WEB-INF/struts-tags.tld</taglib-location>
        </taglib>

        <taglib>
            <taglib-uri>sitemesh-page</taglib-uri>
            <taglib-location>/WEB-INF/sitemesh-page.tld</taglib-location>
        </taglib>

        <taglib>
            <taglib-uri>sitemesh-decorator</taglib-uri>
            <taglib-location>/WEB-INF/sitemesh-decorator.tld</taglib-location>
        </taglib>
    </jsp-config>
    
  
    <welcome-file-list>
        <welcome-file>/jsp/Login.jsp</welcome-file>
    </welcome-file-list>

     <context-param>
  <param-name>authority</param-name>
  <param-value>https://login.windows.net/</param-value>
 </context-param>
 <context-param>
  <param-name>contextConfigLocation</param-name>
  <param-value>/WEB-INF/mvc-dispatcher-servlet.xml</param-value>
 </context-param>

 <context-param>
  <param-name>tenant</param-name>
  <param-value>mytenat</param-value>
 </context-param>
 
 <filter-mapping>
  <filter-name>BasicFilter</filter-name>
  <url-pattern>/*</url-pattern>
 </filter-mapping>
  <filter>
  <filter-name>BasicFilter</filter-name>
  <filter-class>mx.prototype.adaj4jAzure.BasicFilter</filter-class>
  <init-param>
   <param-name>client_id</param-name>
   <param-value>myclientid</param-value>
  </init-param>
  <init-param>
   <param-name>secret_key</param-name>
   <param-value>secretkeyy</param-value>
  </init-param>
 </filter>
  <servlet>
  <servlet-name>mvc-dispatcher</servlet-name>
  <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
  <load-on-startup>1</load-on-startup>
 </servlet>
 <servlet-mapping>
  <servlet-name>mvc-dispatcher</servlet-name>
  <url-pattern>/</url-pattern>
 </servlet-mapping>
    
</web-app>

my struts.xml

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE struts PUBLIC
    "-//Apache Software Foundation//DTD Struts Configuration 2.5//EN"
    "http://struts.apache.org/dtds/struts-2.5.dtd">
    
<struts>

<!--    
    <constant name="struts.enable.DynamicMethodInvocation" value="true"/>
    <constant name="struts.devMode" value="false" />
    <constant name="struts.configuration.xml.reload" value="false" />
    <constant name="struts.i18n.reload" value="false" />
    <constant name="struts.custom.i18n.resources" value="ApplicationResources" />
    <constant name="struts.multipart.maxSize" value="5242880"/>
   -->
   
    <constant name="struts.enable.DynamicMethodInvocation" value="true"/>
    <constant name="struts.custom.i18n.resources" value="ApplicationResources" />
    <constant name="struts.multipart.maxSize" value="524288000" />
    <constant name="struts.devMode" value="false" />    
    <constant name="struts.i18n.reload" value="false"/>
    <constant name="struts.configuration.xml.reload" value="false"/>
    <constant name="struts.freemarker.templatesCache" value="true"/>
    <constant name="struts.freemarker.templatesCache.updateDelay" value="120"/>
    <constant name="struts.freemarker.mru.max.strong.size" value="120"/>
    <constant name="struts.action.excludePattern" value="/struts/webconsole.html" />
    <constant name="struts.action.excludePattern" value="/struts/webconsole.css"/>
    <constant name="struts.action.excludePattern" value="/struts/webconsole.js"/>

    <include file="strutsDomain.xml"/>
    <include file="strutsLogin.xml"/>
    <include file="strutsPasswordParameters.xml"/>
    <include file="strutsPersonalize.xml"/>
    <include file="strutsProfile.xml"/>
    <include file="strutsTemplate.xml"/>
    <include file="strutsRoute.xml"/>
    <include file="strutsPlantillas.xml"/>
   
    <package name="serveAll" namespace="" extends="struts-default">
        <action name="*">
            <result>/jsp/common/error.jsp</result>
        </action>
    </package>
</struts>
over 4 years ago · Santiago Trujillo
Responde la pregunta
Encuentra empleos remotos

¡Descubre la nueva forma de encontrar empleo!

Top de empleos
Top categorías de empleo
Empresas
Publicar vacante Precios Comercial
Legal
Términos y condiciones Política de privacidad
© 2026 PeakU Inc. All Rights Reserved.
Andres GPT
Recomiéndame algunas ofertas
Necesito ayuda