Environment
NetIQ Access Manager 4.0
NetIQ Access Manager 4.1
NetIQ Access Manager Identity Server on Linux or Windows
Kerberos contract with fallback property enabled to prompt users for username/password when no valid token presented
Problem only exists with IE and not Firefox or Chrome
NetIQ Access Manager 4.1
NetIQ Access Manager Identity Server on Linux or Windows
Kerberos contract with fallback property enabled to prompt users for username/password when no valid token presented
Problem only exists with IE and not Firefox or Chrome
Situation
Access Gateway (AG) setup to accelerate Sharepoint (SP)
back end server, where Sharepoint authenticates users against an AD store. The Sharepoint protected resources require authentication at the Identity (IDP) server with their Kerberos token. Kerberos is configured with Fall Back method - protected password class in our case - using the fallback property.
All appears to be working fine, although one specific use case is returning non standard behaviour. When users access the Sharepoint protected resource from an outside network, they do so without any kerberos token. These users correctly fall back to the username/password prompt associated with the fallback method. If the user does not submit their username and password immediately, but waits for 60 seconds or more before submitting credentials, the user will NOT be authenticated but will be prompted to authenticate with their credentials again.
This only seems to happen with IE - Firefox and Chrome work fine.
All appears to be working fine, although one specific use case is returning non standard behaviour. When users access the Sharepoint protected resource from an outside network, they do so without any kerberos token. These users correctly fall back to the username/password prompt associated with the fallback method. If the user does not submit their username and password immediately, but waits for 60 seconds or more before submitting credentials, the user will NOT be authenticated but will be prompted to authenticate with their credentials again.
This only seems to happen with IE - Firefox and Chrome work fine.
Resolution
Need to modify certain JSPs to workaround the issue with IE.
1. take a backup of existing top.jsp (/opt/novell/nam/idp/webapps/nidp/jsp//top.jsp) from IDP server
2. copy the modified top.jsp and new fallback.jsp below to the IDP servers jsp folder (/opt/novell/nam/idp/webapps/nidp/jsp/)
3. Add fallback.jsp to the allowed list of jsp's on the IDP server by modifying the /opt/novell/nam/idp/webapps/nidp/WEB-INF/web.xml file with the following change (added fallback.jsp to end)
<init-param>
<param-name>publicAccess</param-name>
<param-value>main.jsp;err.jsp;err2.jsp;login.jsp;nmaslogin.jsp;logoutSuccess.jsp;banner.jsp;nav.jsp;menus.jsp;footer.jsp;content.jsp;cards.jsp;title.jsp;error.jsp;curcard.jsp;createacct.jsp;x509err.jsp;clearCookieAuth.jsp;totpregistration.jsp;socialauth.jsp;socialauth_provision.jsp;socialauth_return.jsp;fallback.jsp</param-value>
</init-param>
4. Make sure kerberos class is configured to the fall back jsp of 'fallback' (https://www.netiq.com/documentation/netiqaccessmanager4_appliance/identityserverhelp/data/b9ud20f.html#fallback_auth)
5. restart IDP using 'rcnovell-idp restart'
// top.jsp changes
<%@ page language="java" %>
<%@ page contentType="text/html" %>
<%@ page import="com.novell.nidp.ui.*" %>
<%
UIHandler uh = new UIHandler(request,response);
String url = (String) request.getAttribute("url");
if(request.getAttribute("idffbaseurl") != null && url.startsWith("sso?"))
{
url = (String) request.getAttribute("idffbaseurl") + url;
}
%>
<!DOCTYPE HTML PUBLIC "-//W3C//Dtd HTML 4.0 transitional//<%=uh.getLanguageCode()%>">
<html lang="<%=uh.getLanguageCode()%>">
<head>
<META HTTP-EQUIV="expires" CONTENT="0">
</head>
<body>
<script language="JavaScript">
<!--
top.location.href='<%=url%>';
-->
</script>
</body>
</html>
// fallback.jsp changes
<%@page import="com.novell.nidp.wsfed.protocol.WSFedAuthnRequest"%>
<%@page import="com.novell.nidp.common.protocol.AuthnRequest"%>
<%@ page language="java" %>
<%@ page pageEncoding="UTF-8" contentType="text/html; charset=UTF-8"%>
<%@ page import="java.util.*" %>
<%@ page import="com.novell.nidp.*" %>
<%@ page import="com.novell.nidp.servlets.*" %>
<%@ page import="com.novell.nidp.resource.*" %>
<%@ page import="com.novell.nidp.resource.jsp.*" %>
<%@ page import="com.novell.nidp.ui.*" %>
<%@ page import="org.apache.commons.lang.StringEscapeUtils" %>
<%@page import="java.net.URL"%>
<%
if(request.getMethod() == "POST" && request.getAttribute("idffbaseurl") == null)
{
// Actual destination
String destinationURI = request.getParameter("destinationuri");
URL url = new URL(destinationURI);
// set idffbaseurl to use it with top.jsp
request.setAttribute("idffbaseurl", destinationURI.substring(0,destinationURI.lastIndexOf("/")+1));
// forward to destination url
request.getRequestDispatcher(url.getFile().substring(5)).forward(request, response);
return;
}
%>
<%
ContentHandler handler = new ContentHandler(request,response);
String target = (String) request.getAttribute("target");
String uname = (String)request.getAttribute("username");
NIDPSessionData sData = NIDPContext.getNIDPContext().getSession(request).getSessionData(request.getParameter("sid"));
AuthnRequest proxyReq = sData.getProxiedRequest();
if(proxyReq instanceof WSFedAuthnRequest)
uname = ((WSFedAuthnRequest)proxyReq).getParameter("username");
if ( uname == null )
uname = "";
uname = StringEscapeUtils.escapeHtml(uname);
if ( target != null )
target = StringEscapeUtils.escapeHtml(target);
%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//<%=handler.getLanguageCode()%>">
<html lang="<%=handler.getLanguageCode()%>">
<head>
<META HTTP-EQUIV="Content-Language" CONTENT="<%=handler.getLanguageCode()%>">
<meta http-equiv="content-type" content="text/html;charset=utf-8">
<meta name = "viewport" content = "user-scalable=yes, initial-scale=1.0, maximum-scale=1.0, width=device-width" >
<style type="text/css" media="screen">
td label { font-size: 0.85em ; padding-right: 0.2em; }
label { font-size: 0.77em; padding-right: 0.2em; }
input { font-family: sans-serif; }
input[type=text],input[type=password],textarea { width:200px;}
.instructions { color: #4d6d8b; font-size: 0.8em; margin: 0 10px 10px 0 }
@media only screen and (max-width: 800px) {
input[type=text],input[type=password], textarea{
width:225px;
}}/* 320 */
@media only screen and (max-width : 800px)
{
.labelshow{display:none;}
.placeholder{display: block;}
}/* 480 */
@media only screen and (min-width : 801px)
{
.placeholder{display: none;}
}/* 480 */
</style>
<script src="/nidp/javascript/jquery-1.8.2.min.js"></script>
<script src="/nidp/javascript/jquery.min.js"></script>
<script type="text/javascript" src="<%= handler.getImage("showhide_2.js",false)%>"></script>
<script language="JavaScript">
var i = 0;
function imageSubmit()
{
if (i == 0)
{
i = 1;
document.IDPLogin.submit();
}
return false;
}
function onLoadFocus()
{
if(document.IDPLogin.Ecom_User_ID.value)
document.IDPLogin.Ecom_Password.focus();
else
document.IDPLogin.Ecom_User_ID.focus();
}
$(function() {
if(screen.width > 1600 )/* 480 */
$('.placeholderclass').removeAttr('placeholder');
});
</script>
<script src="/nidp/javascript/login_jsp.js"></script>
</head>
<body style="background-color: <%=handler.getBGColor()%>" marginwidth="0" marginheight="0" leftmargin="0" topmargin="0" rightmargin="0" >
<form name="IDPLogin" enctype="application/x-www-form-urlencoded" method="POST" action="/nidp/jsp/fallback.jsp" AUTOCOMPLETE="off">
<input type="hidden" name="option" value="credential">
<% if (target != null) { %>
<input type="hidden" name="target" value="<%=target%>">
<% } %>
<table border=0 style="margin-top: 1em" width="100%" cellspacing="0" cellpadding="0">
<tr>
<td style="padding: 0px">
<table border=0>
<tr>
<td align=left>
<label class="labelshow"><%=handler.getResource(JSPResDesc.USERNAME)%></label>
</td>
<td align=left>
<label class="placeholder"><%=handler.getResource(JSPResDesc.USERNAME)%><br></label>
<input type="text" name="Ecom_User_ID" value="<%=uname%>" class="placeholderclass" >
</td>
</tr>
<tr>
<td align=left>
<label class="labelshow"><%=handler.getResource(JSPResDesc.PASSWORD)%></label>
</td>
<td align=left>
<label class="placeholder"><%=handler.getResource(JSPResDesc.PASSWORD)%><br></label>
<input type="password" name="Ecom_Password" class="placeholderclass" >
</td>
</tr>
<tr>
<td align=right colspan=2 style="white-space: nowrap">
<input alt="<%=handler.getResource(JSPResDesc.LOGIN)%>" border="0" name="loginButton2" src="<%= handler.getImage("btnlogin.gif",true)%>" type="image" value="Login" onClick="return imageSubmit()">
</td>
</tr>
</table>
</td>
</tr>
<%
String err = (String) request.getAttribute(NIDPConstants.ATTR_LOGIN_ERROR);
if (err != null)
{
%>
<td style="padding: 10px">
<div class="instructions"><%=err%></div>
</td>
</tr>
<% } %>
<%
if (NIDPCripple.isCripple())
{
%>
<tr>
<td width="100%" align="center"><%=NIDPCripple.getCrippleAdvertisement(request.getLocale())%></td>
</tr>
<%
}
%>
<%
Object enabled = (Boolean) request.getAttribute(NIDPConstants.ATTR_REMEMBERME_OPTION);
if(enabled != null && (Boolean) enabled)
{
%>
<tr>
<td align=left>
<input type="checkbox" name="EnableCookieAuth" value="true" /> <label> Remember Me </label>
</td>
</tr>
<tr></tr>
<tr> <td> <span class="instructions"> (Do not check this box if you are using public computer.)</span> </td></tr>
<%
}
%>
</table>
<input type=hidden name="destinationuri" value="<%= (String) request.getAttribute("url") %>">
</form>
</body>
</html>
1. take a backup of existing top.jsp (/opt/novell/nam/idp/webapps/nidp/jsp//top.jsp) from IDP server
2. copy the modified top.jsp and new fallback.jsp below to the IDP servers jsp folder (/opt/novell/nam/idp/webapps/nidp/jsp/)
3. Add fallback.jsp to the allowed list of jsp's on the IDP server by modifying the /opt/novell/nam/idp/webapps/nidp/WEB-INF/web.xml file with the following change (added fallback.jsp to end)
<init-param>
<param-name>publicAccess</param-name>
<param-value>main.jsp;err.jsp;err2.jsp;login.jsp;nmaslogin.jsp;logoutSuccess.jsp;banner.jsp;nav.jsp;menus.jsp;footer.jsp;content.jsp;cards.jsp;title.jsp;error.jsp;curcard.jsp;createacct.jsp;x509err.jsp;clearCookieAuth.jsp;totpregistration.jsp;socialauth.jsp;socialauth_provision.jsp;socialauth_return.jsp;fallback.jsp</param-value>
</init-param>
4. Make sure kerberos class is configured to the fall back jsp of 'fallback' (https://www.netiq.com/documentation/netiqaccessmanager4_appliance/identityserverhelp/data/b9ud20f.html#fallback_auth)
5. restart IDP using 'rcnovell-idp restart'
// top.jsp changes
<%@ page language="java" %>
<%@ page contentType="text/html" %>
<%@ page import="com.novell.nidp.ui.*" %>
<%
UIHandler uh = new UIHandler(request,response);
String url = (String) request.getAttribute("url");
if(request.getAttribute("idffbaseurl") != null && url.startsWith("sso?"))
{
url = (String) request.getAttribute("idffbaseurl") + url;
}
%>
<!DOCTYPE HTML PUBLIC "-//W3C//Dtd HTML 4.0 transitional//<%=uh.getLanguageCode()%>">
<html lang="<%=uh.getLanguageCode()%>">
<head>
<META HTTP-EQUIV="expires" CONTENT="0">
</head>
<body>
<script language="JavaScript">
<!--
top.location.href='<%=url%>';
-->
</script>
</body>
</html>
// fallback.jsp changes
<%@page import="com.novell.nidp.wsfed.protocol.WSFedAuthnRequest"%>
<%@page import="com.novell.nidp.common.protocol.AuthnRequest"%>
<%@ page language="java" %>
<%@ page pageEncoding="UTF-8" contentType="text/html; charset=UTF-8"%>
<%@ page import="java.util.*" %>
<%@ page import="com.novell.nidp.*" %>
<%@ page import="com.novell.nidp.servlets.*" %>
<%@ page import="com.novell.nidp.resource.*" %>
<%@ page import="com.novell.nidp.resource.jsp.*" %>
<%@ page import="com.novell.nidp.ui.*" %>
<%@ page import="org.apache.commons.lang.StringEscapeUtils" %>
<%@page import="java.net.URL"%>
<%
if(request.getMethod() == "POST" && request.getAttribute("idffbaseurl") == null)
{
// Actual destination
String destinationURI = request.getParameter("destinationuri");
URL url = new URL(destinationURI);
// set idffbaseurl to use it with top.jsp
request.setAttribute("idffbaseurl", destinationURI.substring(0,destinationURI.lastIndexOf("/")+1));
// forward to destination url
request.getRequestDispatcher(url.getFile().substring(5)).forward(request, response);
return;
}
%>
<%
ContentHandler handler = new ContentHandler(request,response);
String target = (String) request.getAttribute("target");
String uname = (String)request.getAttribute("username");
NIDPSessionData sData = NIDPContext.getNIDPContext().getSession(request).getSessionData(request.getParameter("sid"));
AuthnRequest proxyReq = sData.getProxiedRequest();
if(proxyReq instanceof WSFedAuthnRequest)
uname = ((WSFedAuthnRequest)proxyReq).getParameter("username");
if ( uname == null )
uname = "";
uname = StringEscapeUtils.escapeHtml(uname);
if ( target != null )
target = StringEscapeUtils.escapeHtml(target);
%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//<%=handler.getLanguageCode()%>">
<html lang="<%=handler.getLanguageCode()%>">
<head>
<META HTTP-EQUIV="Content-Language" CONTENT="<%=handler.getLanguageCode()%>">
<meta http-equiv="content-type" content="text/html;charset=utf-8">
<meta name = "viewport" content = "user-scalable=yes, initial-scale=1.0, maximum-scale=1.0, width=device-width" >
<style type="text/css" media="screen">
td label { font-size: 0.85em ; padding-right: 0.2em; }
label { font-size: 0.77em; padding-right: 0.2em; }
input { font-family: sans-serif; }
input[type=text],input[type=password],textarea { width:200px;}
.instructions { color: #4d6d8b; font-size: 0.8em; margin: 0 10px 10px 0 }
@media only screen and (max-width: 800px) {
input[type=text],input[type=password], textarea{
width:225px;
}}/* 320 */
@media only screen and (max-width : 800px)
{
.labelshow{display:none;}
.placeholder{display: block;}
}/* 480 */
@media only screen and (min-width : 801px)
{
.placeholder{display: none;}
}/* 480 */
</style>
<script src="/nidp/javascript/jquery-1.8.2.min.js"></script>
<script src="/nidp/javascript/jquery.min.js"></script>
<script type="text/javascript" src="<%= handler.getImage("showhide_2.js",false)%>"></script>
<script language="JavaScript">
var i = 0;
function imageSubmit()
{
if (i == 0)
{
i = 1;
document.IDPLogin.submit();
}
return false;
}
function onLoadFocus()
{
if(document.IDPLogin.Ecom_User_ID.value)
document.IDPLogin.Ecom_Password.focus();
else
document.IDPLogin.Ecom_User_ID.focus();
}
$(function() {
if(screen.width > 1600 )/* 480 */
$('.placeholderclass').removeAttr('placeholder');
});
</script>
<script src="/nidp/javascript/login_jsp.js"></script>
</head>
<body style="background-color: <%=handler.getBGColor()%>" marginwidth="0" marginheight="0" leftmargin="0" topmargin="0" rightmargin="0" >
<form name="IDPLogin" enctype="application/x-www-form-urlencoded" method="POST" action="/nidp/jsp/fallback.jsp" AUTOCOMPLETE="off">
<input type="hidden" name="option" value="credential">
<% if (target != null) { %>
<input type="hidden" name="target" value="<%=target%>">
<% } %>
<table border=0 style="margin-top: 1em" width="100%" cellspacing="0" cellpadding="0">
<tr>
<td style="padding: 0px">
<table border=0>
<tr>
<td align=left>
<label class="labelshow"><%=handler.getResource(JSPResDesc.USERNAME)%></label>
</td>
<td align=left>
<label class="placeholder"><%=handler.getResource(JSPResDesc.USERNAME)%><br></label>
<input type="text" name="Ecom_User_ID" value="<%=uname%>" class="placeholderclass" >
</td>
</tr>
<tr>
<td align=left>
<label class="labelshow"><%=handler.getResource(JSPResDesc.PASSWORD)%></label>
</td>
<td align=left>
<label class="placeholder"><%=handler.getResource(JSPResDesc.PASSWORD)%><br></label>
<input type="password" name="Ecom_Password" class="placeholderclass" >
</td>
</tr>
<tr>
<td align=right colspan=2 style="white-space: nowrap">
<input alt="<%=handler.getResource(JSPResDesc.LOGIN)%>" border="0" name="loginButton2" src="<%= handler.getImage("btnlogin.gif",true)%>" type="image" value="Login" onClick="return imageSubmit()">
</td>
</tr>
</table>
</td>
</tr>
<%
String err = (String) request.getAttribute(NIDPConstants.ATTR_LOGIN_ERROR);
if (err != null)
{
%>
<td style="padding: 10px">
<div class="instructions"><%=err%></div>
</td>
</tr>
<% } %>
<%
if (NIDPCripple.isCripple())
{
%>
<tr>
<td width="100%" align="center"><%=NIDPCripple.getCrippleAdvertisement(request.getLocale())%></td>
</tr>
<%
}
%>
<%
Object enabled = (Boolean) request.getAttribute(NIDPConstants.ATTR_REMEMBERME_OPTION);
if(enabled != null && (Boolean) enabled)
{
%>
<tr>
<td align=left>
<input type="checkbox" name="EnableCookieAuth" value="true" /> <label> Remember Me </label>
</td>
</tr>
<tr></tr>
<tr> <td> <span class="instructions"> (Do not check this box if you are using public computer.)</span> </td></tr>
<%
}
%>
</table>
<input type=hidden name="destinationuri" value="<%= (String) request.getAttribute("url") %>">
</form>
</body>
</html>