错误 404:javax.servlet.ServletException:java.io.FileNotFoundException:SRVE0190E:找不到文件:/oidcclient/redirect/MyRP

Error 404: javax.servlet.ServletException: java.io.FileNotFoundException: SRVE0190E: File not found: /oidcclient/redirect/MyRP

我正在尝试将 AppID 服务与我的 spring 应用程序集成。为此,我在 MyAppId 服务 -> 管理 -> 身份验证设置下添加了 redirect-uri https://app-host-name:port-number/oidcclient/redirect/MyRP 用于重定向回应用程序 验证用户凭据后。

现在的问题是,当用户在输入凭据后尝试登录应用程序时,它不会重定向到我在应用程序代码中指定的 uri,而是给出主题中提到的 404 代码。

请检查以下特定于 AppID 实现部分的指定代码,并建议我解决此问题。

应用技术栈如下:-

1.Spring (4.3.0.RELEASE)
2.Spring Security (4.1.1.RELEASE)
3.Websphere Liberty (20.0.0.1)

我已经根据 https://github.com/ibm-cloud-security/app-id-sample-java

上 AppID 的 IBM 官方代码存储库实施了集成代码

在应用程序代码中所做的更改如下:-

server.xml

<!-- Enable features -->
<featureManager>
    <feature>jsp-2.3</feature>
    <feature>localConnector-1.0</feature>
    <!-- Features for APP ID -->
    <feature>servlet-3.1</feature>
    <feature>appSecurity-2.0</feature>
    <feature>openidConnectClient-1.0</feature>
    <feature>ssl-1.0</feature>
</featureManager>

<!-- To access this server from a remote client add a host attribute to the following element, e.g. host="*" -->
<httpEndpoint httpPort="9080" httpsPort="9443" id="defaultHttpEndpoint"/>
              
<!-- Automatically expand WAR files and EAR files -->
<applicationManager autoExpand="true" startTimeout="15m"/>


<applicationMonitor updateTrigger="mbean"/>

<keyStore id="defaultKeyStore" password="${keystore_password}"/>
<keyStore id="digicertRootCA" location="${server.config.dir}/resources/security/digicert-root-ca.jks" password="digicert"/>
<ssl id="oidcClientSSL" keyStoreRef="defaultKeyStore" trustStoreRef="digicertRootCA"/>



  <authFilter id="myAuthFilter">
    <requestUrl id="myRequestUrl" urlPattern="/appid_callback" matchType="contains"/>
</authFilter>


<openidConnectClient id="MyRP"
                     clientId="${env.APP_ID_CLIENT_ID}"
                     clientSecret= "${env.APP_ID_CLIENT_SECRET}"
                     authorizationEndpointUrl="${env.APP_ID_OAUTH_SERVER_URL}/authorization"
                     tokenEndpointUrl="${env.APP_ID_OAUTH_SERVER_URL}/token"
                     jwkEndpointUrl="${env.APP_ID_OAUTH_SERVER_URL}/publickeys"
                     issuerIdentifier="${env.APP_ID_ISSUER_IDENTIFIER}"
                     tokenEndpointAuthMethod="basic"
                     signatureAlgorithm="RS256"
                     authFilterid="myAuthFilter"
                     redirectToRPHostAndPort="https://${env.APP_ID_HOSTNAME}.${env.APP_ID_DOMAIN}"
/> 
 
<application id="ne" location="ne-1.0.0-BUILD-SNAPSHOT.war" name="ne">
    <application-bnd>
        <security-role name="appidrole">
                    <special-subject type="ALL_AUTHENTICATED_USERS" />
        </security-role>
    </application-bnd>
 </application>  
 

web.xml

<web-app 
xmlns="http://xmlns.jcp.org/xml/ns/javaee" 
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd" 
version="3.1">

<display-name>MyWebApp</display-name>

<security-role>
    <role-name>appidrole</role-name>
</security-role>

<servlet>
    <servlet-name>AppIdCallbackServlet</servlet-name>
    <servlet-class>com.example.appid.AppIdCallBackServlet</servlet-class>
</servlet>

<servlet>
    <servlet-name>LogoutServlet</servlet-name>
    <servlet-class>com.example.appid.AppIdLogoutServlet</servlet-class>
</servlet>

<servlet-mapping>
    <servlet-name>AppIdCallbackServlet</servlet-name>
    <url-pattern>/appid_callback</url-pattern>
</servlet-mapping>

<servlet-mapping>
    <servlet-name>LogoutServlet</servlet-name>
    <url-pattern>/logout</url-pattern>
</servlet-mapping>

<security-constraint>
    <display-name>Security Constraints</display-name>
    <web-resource-collection>
        <web-resource-name>Security Constraint</web-resource-name>
        <url-pattern>/appid_callback/*</url-pattern>
        <http-method>GET</http-method>
        <http-method>PUT</http-method>
        <http-method>POST</http-method>
        <http-method>DELETE</http-method>
    </web-resource-collection>
    <auth-constraint>
        <role-name>appidrole</role-name>
    </auth-constraint>
    <user-data-constraint>
        <transport-guarantee>NONE</transport-guarantee>
    </user-data-constraint>
</security-constraint>

<!-- <filter>
    <filter-name>FilterToGetTimeOut </filter-name> 
    <filter-class>example.common.filter.FilterToGetTimeOut </filter-class> 
</filter>
<filter-mapping> 
    <filter-name>FilterToGetTimeOut</filter-name> 
    <url-pattern>/*</url-pattern> 
</filter-mapping> -->

<session-config>
    <session-timeout>20</session-timeout>
</session-config>   

映射

@RequestMapping(value="/", method=RequestMethod.GET)
public String appidCallbackMapping(HttpServletRequest request, HttpServletResponse response)
{
    logger.info("present in appid callback mapping method created in UserController.java ===> deepanshu.l@hcl.com");
    Authentication auth = SecurityContextHolder.getContext().getAuthentication();
    String idTokenRaw = null;
    try {
        idTokenRaw = getIDToken();
    } catch (IOException e2) {
        // TODO Auto-generated catch block
        e2.printStackTrace();
    }
    logger.info("calling getIdToken before checking whether auth object instanceof AnonymousAuthenticationToken ===> deepanshu.l@hcl.com");
    logger.info("idToken Value :- " + idTokenRaw);
    if (!(auth instanceof AnonymousAuthenticationToken)) {
        logger.info("authentication object found not to be an instance of AnonymousAuthenticationToken (successfully )===> deepanshu.l@hcl.com");
         try {
             idTokenRaw = getIDToken();
             logger.info("inside check of AnonymousAuthenticationToken --> tokenValue ===> " + idTokenRaw);
             if (idTokenRaw != null) {
                    String idTokenPayload = getTokenPayload(idTokenRaw);
                    // save the id_token and user's name on the request so that
                    // they can be passed on to UI elements
                    JSONObject idTokenContent = JSONObject.parse(idTokenPayload);
                    String username = idTokenContent.get("name").toString();
                    logger.info("Username value retrieved from appid token :- " + username);
                //    request.setAttribute("name", username);
                //   request.setAttribute("id_token", idTokenPayload);
                } else {
                    logger.info("No id_token located via security context");
                }
        } catch (IOException e1) {
            // TODO Auto-generated catch block
            e1.printStackTrace();
        }
         UserDetails userDetail=null;
         userDetail = (UserDetails) auth.getPrincipal();
         ObjectMapper objectMapper = new ObjectMapper();
         try {
            logger.info(objectMapper.writeValueAsString(auth));
        } catch (JsonProcessingException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
         
         String userId= userDetail.getUsername();
         
        logger.info("User Id of the user as follows :- " + userId); 
        return "redirect:/company";
    }
    else
        return "redirect:/appid_callback";
                
}

   private String getIDToken() throws IOException{
    Subject wasSubj;
    try {
        wasSubj = WSSubject.getRunAsSubject();
    } catch (WSSecurityException e) {
        // In real applications, exception should be handled better
        throw new IOException(e);
    }

    Set<Hashtable> creds = wasSubj.getPrivateCredentials(Hashtable.class);

    for (Hashtable hTable : creds) {
        if (hTable.containsKey("id_token")) {
            return hTable.get("id_token").toString();
        }
    }
    //return null if not found
    return null;
}

 private String getTokenPayload(String token) {
        String payload64 = token.split("\.")[1];
        String payload = new String(Base64.decodeBase64(payload64));
        return payload;
    }

AppIdCallBackServlet.java

public class AppIdCallBackServlet extends HttpServlet {

private static final long serialVersionUID = 1L;

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

/**
 * @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse response)
 */
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

    logger.info("present in doGet nethod of appIdCallback method ==> deepanshu.l@hcl.com");
    
    response.setContentType("text/html;charset=utf-8");
    PrintWriter out = response.getWriter();
    try {
        String idTokenRaw = getIDToken();
        if (idTokenRaw != null) {
            String idTokenPayload = getTokenPayload(idTokenRaw);
            // save the id_token and user's name on the request so that
            // they can be passed on to UI elements
            JSONObject idTokenContent = JSONObject.parse(idTokenPayload);
            String username = idTokenContent.get("name").toString();
            logger.info("username value retrieved from token and currently present in AppIdCallbackServlet.java file ===> " + username);
            request.setAttribute("name", username);
            request.setAttribute("id_token", idTokenPayload);
        } else {
            out.println("No id_token located via security context");
        }
    } catch (Exception e) {
        // In real applications, exception should be handled better
        e.printStackTrace(out);
    }
    request.getRequestDispatcher("/").forward(request, response);
}

private String getTokenPayload(String token) {
    String payload64 = token.split("\.")[1];
    String payload = new String(Base64.decodeBase64(payload64));
    return payload;
}

/*
This method uses Liberty API to extract a Hashtable object that contains
the App ID tokens.
 */
private String getIDToken() throws IOException{
    Subject wasSubj;
    try {
        wasSubj = WSSubject.getRunAsSubject();
    } catch (WSSecurityException e) {
        // In real applications, exception should be handled better
        throw new IOException(e);
    }

    Set<Hashtable> creds = wasSubj.getPrivateCredentials(Hashtable.class);

    for (Hashtable hTable : creds) {
        if (hTable.containsKey("id_token")) {
            return hTable.get("id_token").toString();
        }
    }
    //return null if not found
    return null;
}
  }

SecurityConfig.java

  @Override 
  protected void configure(HttpSecurity http) throws Exception {
      http.authorizeRequests().antMatchers("/**").permitAll();
  }

在server.xml而不是<keyStore id="defaultKeyStore" password="${keystore_password}"/> <keyStore id="digicertRootCA" location="${server.config.dir}/resources/security/digicert-root-ca.jks" password="digicert"/> <ssl id="oidcClientSSL" keyStoreRef="defaultKeyStore" trustStoreRef="digicertRootCA"/>

尝试使用 <keyStore id="defaultKeyStore" password="${keystore_password}"/> <ssl id="oidcClientSSL" keyStoreRef="defaultKeyStore" trustDefaultCerts="true" />