错误 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" />
我正在尝试将 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" />