This discussion has been locked.
You can no longer post new replies to this discussion. If you have a question you can start a new discussion

Access Manager should support RADIUS from external MFA solutions

During integration of Azure MFA and NAM, the integration failed and we detected it is from NAM side. Was  installed 3 other free radius servers and did the integration and it worked perfectly. Knowing that we have integrated Azure MFA using same way (RADIUS) with Beyondtrust, Safeguard, Okta and other third party products and it should working fine.

When we opened the case with support, they said this is not tested before and they cannot say it is a defect because they never said it is supported. Even not agreeing with this because it is a standard RADIUS integration and Azure MFA uses PAP protocol that is standard. The reply was they don’t support every RADIUS product. Once you support RADIUS, it is standard. Anyway they said it might be a missing parameter but in order to proceed with it they want to know the value of the business opportunity (that is because they don’t want to consider it as defect). So now customer is saying if this will not work, they will use Microsoft Azure AD SSO.

  • 0  

    Hi!

    During integration of Azure MFA and NAM, the integration failed and we detected it is from NAM side

    Can you also elaborate what was actual error/problem?

    Kind regards,

    Sebastijan

    Kind regards,

    Sebastijan

    If you found this post useful, give it a “Like” or click on "Verify Answer" under the "More" button

  • 0 in reply to   

    Hello all, 

    Here is Marie-Ange from the partner working on the issue and here are some details: 

    NAM version is 5.0.4. 

    Integration is done using RADIUS with Microsoft NPS server as radius proxy. 

    While testing, the behavior changes because sometimes, we never get a response at all and after restarting NAM services we get a login failure as per below picture and the following error. sometimes the below response is received if we put token in password field and sometimes in token field. 

    Error is: NPS Extension for Azure MFA: NPS Extension for Azure MFA only performs Secondary Auth for Radius requests in AccessAccept State. Request received for User xxxxx with response state AccessReject, ignoring request.

  • 0 in reply to 

    small correction, NAM version is 5.0.3

  • 0   in reply to 

    Hi!

    I see where the problem lies (Azure MFA only performs Secondary Auth for Radius requests) and will write how we solved that problem, but probably won't have time to write it today.

    Will get back to this topic.

    Kind regards,

    Sebastijan

    Kind regards,

    Sebastijan

    If you found this post useful, give it a “Like” or click on "Verify Answer" under the "More" button

  • 0 in reply to   

    HI Sebasttijan, 

    Thanks for your reply. Did you apply kind of a workaround for this? 

  • Suggested Answer

    0   in reply to 

    Hi Maria!

    Let me explain what we did. Please note that we were doing only Access Manager stuff, NPS server was configured by some other guy.

    So prerequisite is that NPS is able to authenticate user using username and OTP in RADIUS request or if sending empty OTP, username and smartphone (reply from server might take some time so NPS server should be properly configured to not immediately reply with failed login)

    So to AM part.

    We have separated this process into two steps, two separate methods connected to same contract.

    This gave us flexibility on both local authentication (could use something else than username/password for first step) and Azure MFA authentication (could use NPS Radius with Azure push authentication)

    First step is standard user authentication you would like to do (we are doing Kerberos with username/password fallback, you can do "standard" username/password, so whatever you like.

    Second step is only secondary authentication/MFA with Azure. So RADIUS is used only for MFA.

    At the end contract looks like this (we also added passwordfetch method to get password when user authenticates using Kerberos):

    Now to the specifics of NPS-Radius-MFA method.

    Method uses standard RADIUS class. When configuring it you need to deselect "Require password", since username/password authentication is already done in first step.

    We also increased reply timeout to 30 seconds to give user's possibility to authenticate when using push/smartphone authentication. NPS will not respond anything until user authenticates using smartphone, so we need to make sure that AM does not timeout too soon.

    This is now a working POC setup. It is extremely unfriendly (we made it much better with custom JSP I will describe this later) but you should first test to see if whole chain works.

    How this contract now behaves? (please note I am writing from top of my mind, so maybe I don't remember all details correctly).

    Of course first step is username/password authentication. But then you are presented with RADIUS class form.

    First manually enter username (I know, username again, but this will be automatically populated later by custom JSP)  and OTP in token field.

    Clicking "sign in" will send that to NPS RADIUS and if entered data is correct, you should be authenticated.

    To authenticate with smartphone push (if it is configured on Azure, of course) enter username and send empty token. This will trigger smartphone authentication. As mentioned before, NPS will not respond to AM until user accepts or declines authentication on smartphone, hence long timeout on RADIUS class.

    If this is now working you should make it pretty, which is done by custom JSP.

    What should custom JSP do? At least fetch username from existing session and populate it in RADIUS form.

    But attached JSP does also something else, since this customer only uses smartphone authentication.

    It fetches current user, populates username and automatically submits form with empty token.

    And of course if error is returned, displays that error to user.

    Please note that this JSP should be used with MainJSP setting set to true.

    I hope this will help you solve the problem.

    Kind regards,

    Sebastijan

    Custom JSP:

    <%@ page language="java" %>
    <%@ page pageEncoding="UTF-8" contentType="text/html; charset=UTF-8"%>
    <%@ page import="com.novell.nidp.*" %>
    <%@ 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" %>
    <%
        ContentHandler handler = new ContentHandler(request,response);
    
        String state     = (String) request.getAttribute("state");
        String challenge = (String) request.getAttribute("challenge");
        String name      = (String) request.getAttribute("name");
        String pwd       = (String) request.getAttribute("password");
    
        String usernameStr       = (String) request.getAttribute("usernameStr");
        usernameStr = (usernameStr != null ? usernameStr : handler.getUserName());
        boolean doPassword = false;
        boolean doChallenge = false;
    
    
        if (pwd != null)
            doPassword = true;
    
        if (state != null && name != null)
            doChallenge = true;
    
        if (name != null)
            name = StringEscapeUtils.escapeHtml(name);
        if (challenge != null)
        	challenge = StringEscapeUtils.escapeHtml(challenge);
        if (state != null)
            state = StringEscapeUtils.escapeHtml(state);
    
    %>
    <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//<%=handler.getLanguageCode()%>">
    <html lang="<%=handler.getLanguageCode()%>">
    
    	<head>
            <meta http-equiv="X-UA-Compatible" content="IE=8">
            <meta http-equiv="X-UA-Compatible" content="IE=9">
    		<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" >
    
            <link href="../customer/css/bootstrap.min.css" rel="stylesheet">
            <link href="../customer/css/radius.css" rel="stylesheet">
    
            <!--<script type="text/javascript" src="<%= handler.getImage("showhide_2.js",false)%>"></script>-->
    
    
    	</head>
    	<body>
            <script src="/nidp/javascript/respond.js"></script>
            <div class="container">
    		<form name="IDPLogin" class="form-signin" enctype="application/x-www-form-urlencoded" method="POST" action="<%= (String) request.getAttribute("url") %>" AUTOCOMPLETE="off">
    			<input type="hidden" name="option" value="credential">
                <img src="../customer/img/rogfk_farger.jpg" class="form-signin-heading" width="142" height="102">
                <h2 class="form-signin-heading">Velkommen</h2>
    
    
    
                <% if (doChallenge)
                {%>
                <!--Start login with token-->
                    <input type="hidden" name="state" value="<%=state%>">
                    <input type="hidden" name="Ecom_User_ID" value="<%=usernameStr%>">
                    <div class="authentication-info"><%=challenge%></div>
                    <input id="challenge-input-token" type="text" class="form-control" placeholder="Token" name="Ecom_Token" size="30" required="" value="">
                    <button id="challenge-input-button" class="btn btn-lg btn-primary btn-block" type="submit" onclick="loginToken();">Logg inn</button>
    
            <% }
                else
                { %>
                    <!--With token field-->
                    <input type="text" id="input-username" class="form-control" placeholder="Username" name="Ecom_User_ID" size="30" value="<%=usernameStr%>">
                    <input type="hidden" id="input-password" class="form-control" placeholder="Token" name="Ecom_Token" size="30" value="">
                    <button id="input-button" class="btn btn-lg btn-primary btn-block" type="submit" onclick="loginToken();">Logg inn</button>
    
    
            <% }
                if (doPassword)
                { %><p>doPassword</p>
                    <input type="hidden" name="Ecom_User_ID" value="<%=name%>">
                    <input id="password-input-username" type="password" class="form-control" placeholder="Password" name="Ecom_Password" size="30" required=""> <!--Searching for password-->
                    <button  id="password-input-button" class="btn btn-lg btn-primary btn-block" type="submit" onclick="loginToken();">Logg inn</button>
            <% }
                 if (!doChallenge)
                 { %>
                <!--Waiting smartphone-->
                <h3 id="authenticating-user" style="text-align:center" class="hidden-field">Autentiserer bruker</br><%=usernameStr%></h3>
                <img id="authenticating-gif" src="../customer/img/loadercyan.gif"  class="form-signin-heading hidden-field" width="142" height="102">
                <p id="authentication-help" class="authenticating-info" style="text-align:center" class="hidden-field">Waiting for authentication</p>
                 <% }%>
    
    
    
    
    
    <%
        String err = (String) request.getAttribute(NIDPConstants.ATTR_LOGIN_ERROR);
        if (err != null)
        {
    %>
    
    						<div id="authentication-error"><%=err%></div>
    						<script>
                                window.onload = function()
                                {
                                    refreshSite();
                                }
                            </script>
    
    <%  }
        else{%>
            <script>
                window.onload = function()
                {
                    tokenBtn = document.getElementById("input-button");
                    if(tokenBtn != null)
                    {
                        tokenBtn.click();
                    }
                    <%if(doChallenge){%>
                        document.getElementById("authenticating-user").classList.add("hidden-field");
                        document.getElementById("authenticating-gif").style.display="none";
                        document.getElementById("authentication-help").classList.add("hidden-field");
                    <%}%>
                }
            </script>
            <%}%>
    
        <script>
            function loginToken(){
    
                document.getElementById("authenticating-user").classList.remove("hidden-field");
                document.getElementById("authenticating-gif").style.display=null;
                document.getElementById("authentication-help").classList.remove("hidden-field");
    
    
                <% if (err != null)
                {%>
                    document.getElementById("authentication-error").classList.add("hidden-field");
                <% } %>
                <% if (doChallenge)
                {%>
                document.getElementById("challenge-input-token").classList.add("hidden-field");
                document.getElementById("challenge-input-button").classList.add("hidden-field");
                <% }
                else
                { %>
                document.getElementById("input-username").classList.add("hidden-field");
                document.getElementById("input-password").classList.add("hidden-field");
                document.getElementById("input-button").classList.add("hidden-field");
                <% } if (doPassword)
                 { %>
    
                document.getElementById("password-input-username").classList.add("hidden-field");
                document.getElementById("password-input-button").classList.add("hidden-field");
                <% } %>
            }
    
            function refreshSite(){
    
                            document.getElementById("authenticating-user").classList.add("hidden-field");
                            document.getElementById("authenticating-gif").style.display="none";
                            document.getElementById("authentication-help").classList.add("hidden-field");
    
                        <% if (doChallenge)
                        {%>
                        document.getElementById("challenge-input-token").classList.remove("hidden-field");
                        document.getElementById("challenge-input-button").classList.remove("hidden-field");
                        <% }
                        else
                        { %>
                        document.getElementById("input-username").classList.remove("hidden-field");
                        document.getElementById("input-password").classList.remove("hidden-field");
                        document.getElementById("input-button").classList.remove("hidden-field");
                        <% } if (doPassword)
                         { %>
    
                        document.getElementById("password-input-username").classList.remove("hidden-field");
                        document.getElementById("password-input-button").classList.remove("hidden-field");
                        <% } %>
                    }
    
    
        </script>
    
    		</form>
    		</div>
    	</body>
    </html>
    

    Kind regards,

    Sebastijan

    If you found this post useful, give it a “Like” or click on "Verify Answer" under the "More" button