IBM Security Verify

 View Only
Expand all | Collapse all

Forms based SSO - credential pass-through

  • 1.  Forms based SSO - credential pass-through

    Posted Thu November 22, 2018 03:44 AM
    Edited by Michael Boey***** Thu November 22, 2018 03:51 AM
    Hello,

    For migration reasons, we have a requirement for forms-based SSO. I am very much aware that we should move away from this type of integration, but the reality is that we cannot migrate everything to Kerberos / OAuth2 / OIDC / FIDO2 at once. 

    The current situation: 
    User => F5  APM => Application 1 with forms based login
    User => F5  APM => Application 2 with forms based login

    The User enters his/her credentials, and F5 basically stores them in a session and passes them on to the back-end applications. When the user browses to application 2, F5 simply retrieves the credentials from its store and pastes them into the second application. See also AskF5 | Manual Chapter: Form-Based Client-Initiated Single Sign-On Method  . 
    The magic happens in the first step: "The user logs on to Access Policy Manager® and APM® runs the access policy. This populates the session variables with the user credentials."

    Since we are thinking about moving away from F5 APM towards ISAM, we'd like to know if a similar mechanism is available. It seems that the following options exist:
    • GSO: sync passwords to ISAM
    • GSO: enable credential learning
    None of these are ideal, since a) we do not like to sync our passwords to ISAM and b) credential learning will not provide an SSO experience the very first time a user logs in AFTER a password change. Due to password change policies, this might happen quite often. Also, I couldn't get credential learning to work. So I have two main questions:

    Q1: Is there an F5-like capability to simply pass username and password on to the next application?
    We would like to have an 'optimized learning option' where the password is learned immediately upon passing it to ISAM, without ever showing the login page of the RP. This is different from plain password syncing since the password should only be stored for the duration of the session. 
    Has anyone in the community every had a similar requirement, and how did you solve it? My question is similar to this one: IBM Security:IBM Security Identity and Access Management:IBM Security Identity and Access Management:How to pass TAM password to FSSO - IBM Security Identity and Access Management Forum

    Q2: If not, has anyone experience with getting credential learning to work?
    I have added myself to the internal LDAP as GSO user, and my fsso config looks as follows:
    [forms-sso-login-pages]
    login-page-stanza = login-page-one
    login-credential-learning = yes
    [login-page-one]
    login-page = /RDWeb/Pages/en-US/login.aspx*
    login-form-action = *
    login-success-pattern = -200 +302
    gso-resource = rdsgso
    argument-stanza = args-for-login-page-one
    [args-for-login-page-one]
    DomainUserName = gso:username
    UserPass = gso:password
    This config works when manually adding a GSO credential through policy administration. However, learning does not work. 

    Kr,
    Michael

    ------------------------------
    Michael B
    ------------------------------
    ​​


  • 2.  RE: Forms based SSO - credential pass-through
    Best Answer

    Posted Thu November 22, 2018 05:30 AM
    Hi Michael,

    I've heard this request a number of times over the years - the ability for WebSEAL to use the username/password used for authentication for SSO to backend servers.

    The bad news is there's no out-of-the-box way to do this.

    I've always heard two arguments against supporting this:
    • This approach to SSO only works if the user uses uid/pw to authenticate to WebSEAL.  It won't work if user authenticates with federation or EAI or failover cookie etc.
    • It's just a bit nasty to store passwords in session memory

    However, I understand why you're asking for this and, as evidenced by the fact it's possible in other products, it seems like there is a place for it.

    An RFE for this is an option but I'm not sure GSO is really strategic.

    I'm not sure how easy it would be to customize Access Manager to make this work.  Here are a few things I've thought about:

    Store password in user credential at login time
    Storage would be possible using custom authentication with AAC or EAI and you can get attributes for form-based-sso from the credential (doesn't work for Basic Auth though).  This is just a TERRIBLE idea though.  The SAM credential is not an encrypted object and ends up at backend servers quite a lot.  You'd have to be VERY careful not to expose the password by mistake.

    Store password in GSO at login time
    This would be nice.  You'd store the uid/pw in GSO storage during custom login and then it would be available for login to backend server when needed.  Storage in GSO (rather than in session) would mean that it would also be available in subsequent logins that don't use uid/pw.  Combined with auto-learning, this could be a winner.... EXCEPT... I don't think there's any API available to set GSO credentials during login.  Neither registryDirectAPI (which backs the UserLookup helper class) nor SCIM support GSO.

    Store password in GSO at login time (v2)
    There is an option to have Access Manager use an external web service for GSO storage (instead of the built-in storage).  If you implemented a web service to store and retrieve GSO credentials you could the use the idea above because storage of credentials could be managed in a custom login flow using HTTPClient helper.  This is the best I can come up with right now.  It might even be possible to implement the web service as an AAC Authentication Policy (using infomap) which would store the credentials in the runtime DB using ExtMappingCache.

    Perhaps others on the ISAM dev team can think of something else here.  Or they might have strong views about my suggestions above.  Let's see.

    Cheers... Jon.



    ------------------------------
    Jon Harry
    Consulting IT Security Specialist
    IBM
    ------------------------------



  • 3.  RE: Forms based SSO - credential pass-through

    Posted Thu November 22, 2018 05:46 AM
    Hi Michael,

    On question 2, I have previously had credential learning working.

    Looking at your configuration, I suggest the following:

    1) Set a login-form-response-pattern.  In my working configuration I had this set to:
    login-form-response-pattern = *

    2) Set default-login-form-action.  This needs to match the URL used for the POST of the completed login data.  It *does not* include the query string.  I guess you could set it to * but better to have it do a better match on the POST URL.  As a rule, start it with * and then add the last part of the POST URL.  For example:
    default-login-form-action = *login

    Cheers... Jon.

    ------------------------------
    Jon Harry
    Consulting IT Security Specialist
    IBM
    ------------------------------



  • 4.  RE: Forms based SSO - credential pass-through

    Posted Fri November 23, 2018 06:40 AM
    Hi,

    Just to make sure... did you also set gso-credential-learning = yes ? (as opposed to setting login-credential-learning = yes for a junction)

    Kind regards, Peter.

    ------------------------------
    Peter Volckaert
    Sales Engineer
    IBM Security
    ------------------------------



  • 5.  RE: Forms based SSO - credential pass-through

    Posted Fri November 23, 2018 07:39 AM
    Hi Jon,

    Thanks for the suggestions. It seems the web service call for GSO objects is the best solution there is today, however it seems like a complex solution for a simple problem. Perhaps other community members have found an easier way ;). 

    Peter, Jon,
    In the docs about credential learning there is not a clear link to gso-credential-learning. (https://www.ibm.com/support/knowledgecenter/de/SSPREK_9.0.5/com.ibm.isam.doc/wrp_config/reference/ref_fsso_learning_flow.html)

    I did find a document about gso-credential-learning: https://www.ibm.com/support/knowledgecenter/en/SSPREK_9.0.5/com.ibm.isam.doc/wrp_stza_ref/reference/ref_gso_credential_learning.html  , but there is only a mention about BA so I thought it was not relevant. 

    Still, I've tested it by setting a wrong password in my GSO credential, and it seems I get a different error now: 'Error Text: DPWWA2016E No HTML form for single-sign-on was found. ' . So it seems that it might be a combination of Peter's answer and Jon's answer. However, I'm not sure why the form can be found when gso-credential-learning = no and that it cannot be found when gso-credential-learning=yes. 

    Any ideas what impact the gso-credential-learning setting may have on the HTLM form search capabilities?

    My FSSO file now contains the following:
    [forms-sso-login-pages]
    login-page-stanza = login-page-one
    login-credential-learning = yes
    login-form-response-pattern = *

    [login-page-one]
    login-page = /RDWeb/Pages/en-US/login.aspx*
    login-form-action = *
    default-login-form-action = *login.aspx

    login-success-pattern = -200 +302
    gso-resource = rdsgso
    argument-stanza = args-for-login-page-one

    [args-for-login-page-one]
    DomainUserName = gso:username
    UserPass = gso:password


    ------------------------------
    Michael
    ------------------------------



  • 6.  RE: Forms based SSO - credential pass-through

    Posted Fri November 23, 2018 07:56 AM
    Hi Michael,

    My understanding is that gso-credential-learning (in the WebSEAL .conf file) is specifically related to using GSO for completing Basic Authentication on junctions (where -b gso is used on the junction creation command).  I don't think it is relevant to the forms-based SSO that you're attempting.

    You need to have login-credential-learning = yes in the FSSO configuration file but you had that from the start.

    If I remember correctly, you'll see the "No HTML form for single-sign-on was found" error when the request from browser matches login-page but the response from server doesn't include a form with match for login-form-action.

    Maybe the addition of default-login-form-action is having some impact.
    Would it be possible to share the flow of URLs being used and the content of the login.aspx (redacted as necessary)?

    Cheers... Jon.

    ------------------------------
    Jon Harry
    Consulting IT Security Specialist
    IBM
    ------------------------------



  • 7.  RE: Forms based SSO - credential pass-through

    Posted Fri November 23, 2018 08:27 AM
    Edited by Michael Boey***** Fri November 23, 2018 08:27 AM
    ​Hi Jon,

    Thanks for the help.
    So I disabled gso-credential-learning again, and then everything works except for credential learning. I test this as follows:
    • manually set a wrong GSO credential (wrong password)
    • login to the application through ISAM (I have to provide my password)
    • I get access (I'd assume the GSO credential is updated now)
    • Clear cookies
    • Start over => fail: I have to login again at the RP
    The url flow of the app without ISAM is:
    • GET rds.company.com/ => 302 to..
    • GET rds.company.com/RDWeb/ => 302 to..
    • GET rds.company.com/RDWeb/Pages/ => 302 to..
    • GET rds.company.com/RDWeb/Pages/en-US/Default.aspx => 302 to..
    • GET rds.company.com/RDWeb/Pages/en-US/login.aspx?ReturnUrl=/RDWeb/Pages/en-US/Default.aspx => 200
    I then have to login:
    • POST rds.company.com/RDWeb/Pages/en-US/login.aspx?ReturnUrl=%2FRDWeb%2FPages%2Fen-US%2FDefault.aspx => 302 to..
    • GET /RDWeb/Pages/en-US/Default.aspx => 200
    Finish.

    With ISAM, it is largely the same (although each url has /rds in between), I do have added a TOTP authentication mechanism to the /rds resource though, so we pass  both the ISAM login form as well as the TOTP validation screen. The RP has been added as a standard junction at /rds.


    Btw, It seems I had added the 'login-form-response-pattern' in the wrong section. I fixed that in the meantime. So my fsso file is:
    [forms-sso-login-pages]
    login-page-stanza = login-page-one
    login-credential-learning = yes

    [login-page-one]
    login-page = /RDWeb/Pages/en-US/login.aspx*
    login-form-action = *
    default-login-form-action = *login.aspx
    login-form-response-pattern = *

    login-success-pattern = -200 +302
    gso-resource = rdsgso
    argument-stanza = args-for-login-page-one

    [args-for-login-page-one]
    DomainUserName = gso:username
    UserPass = gso:password



    ------------------------------
    Michael
    ------------------------------



  • 8.  RE: Forms based SSO - credential pass-through

    Posted Fri November 23, 2018 08:49 AM
    Hi Michael,

    It would be useful to see how the login page source looks - specifically the "action" in the login form.

    I wonder if having login-form-action = * is appropriate - in the notes for FSSO it says it shouldn't be set like that for learning.  Can you set it to:
    login-form-action = *login.aspx

    (at that point you should also be able to comment out the default-login-form-action)

    Also, can you confirm that on a *failed* login you are directly getting back the login page again (with a 200) rather than being redirected back to the login page (on a 302)?  That behavior is important for the response matching.

    Cheers... Jon.

    ------------------------------
    Jon Harry
    Consulting IT Security Specialist
    IBM
    ------------------------------



  • 9.  RE: Forms based SSO - credential pass-through

    Posted Fri November 23, 2018 09:57 AM

    Hi Jon,
    It is a standard RDS page (MS 2016). I've pasted the html of the form here.

    I've also set the 'login-form-action to *login.aspx and commented out the default action.

    I confirm that a 200 is returned on a failed login.

    So: if i manually set the GSO credentials to the correct values, everything still works. But if i manually set them incorrect, learning does not seem to update them.

          <form id="FrmLogin" name="FrmLogin" action="login.aspx?ReturnUrl=%2FRDWeb%2FPages%2Fen-US%2FDefault.aspx" method="post" onsubmit="return onLoginFormSubmit()">
    
            <input type="hidden" name="WorkSpaceID" value=""/>
            <input type="hidden" name="RDPCertificates" value="**redacted**"/>
            <input type="hidden" name="PublicModeTimeout" value="20"/>
            <input type="hidden" name="PrivateModeTimeout" value="240"/>
            <input type="hidden" name="WorkspaceFriendlyName" value="**redacted**"/>
            <input type="hidden" name="EventLogUploadAddress" value=""/>
            <input type="hidden" name="RedirectorName" value="**redacted**"/>
            <input type="hidden" name="ClaimsHint" value=""/>
            <input type="hidden" name="ClaimsToken" value=""/>
    
            <input name="isUtf8" type="hidden" value="1"/>
            <input type="hidden" name="flags" value="0"/>
    
    
            <table id="tableLoginDisabled" width="300" border="0" align="center" cellpadding="0" cellspacing="0" style="display:none">
    
                <tr id="trWrongAxVersion" style="display:none" >
                <td>
                    <table>
                    <tr>
                        <td height="20">&#160;</td>
                    </tr>
                    <tr>
                        <td><span class="wrng">You don't have the right version of Remote Desktop Connection to use RD Web Access.</span></td>
                    </tr>
                    </table>
                </td>
                </tr>
    
                <tr id="trUnsupportedBrowser" style="display:none" >
                <td>
                    <table>
                    <tr>
                        <td height="20">&#160;</td>
                    </tr>
                    <tr>
                        <td><span class="wrng">Your web browser isn't supported by Microsoft RemoteApp Service. Please use a supported browser.</span></td>
                    </tr>
                    </table>
                </td>
                </tr> 
    
                <tr id="trSupportedBrowserAxLoadError" style="display:none" >
                <td>
                    <table>
                    <tr>
                        <td height="20">&#160;</td>
                    </tr>
                    <tr>
                        <td><span class="wrng">Your browser has ActiveX controls turned off. Go to your browser's settings to turn on ActiveX controls.</span></td>
                    </tr>
                    </table>
                </td>
                </tr> 
    
                <tr id="trCookiesDisabled" style="display:none" >
                <td>
                    <table>
                    <tr>
                        <td height="20">&#160;</td>
                    </tr>
                    <tr>
                        <td><span class="wrng">Your browser has cookies disabled. Go to your browser's settings to enable cookies.</span></td>
                    </tr>
                    </table>
                </td>
                </tr> 
    
                <tr>
                    <td height="50">&#160;</td>
                </tr>
    
            </table>
    
            <table id="tableLoginForm" width="300" border="0" align="center" cellpadding="0" cellspacing="0" style="display:none">
    
                <tr>
                <td height="20">&#160;</td>
                </tr>
    
                <tr>
                <td>
                    <table width="300" border="0" cellpadding="0" cellspacing="0">
                    <tr>
                        <td id="tdDomainUserNameLabel" width="130" align="right" style="display:none">Domain\user name:</td>
                        <td id="tdClaimsDomainUserNameLable" width="130" align="right" style="display:none">Username@domain:</td>
                        <td width="7"></td>
                        <td align="right">
                        <label><input name="DomainUserName" type="text" id="DomainUserName" class="textInputField" size="25" autocomplete="off" /></label>
                        </td>
                    </tr>
                    </table>
                </td>
                </tr>
                <tr>
                <td height="7"></td>
                </tr>
    
                <tr>
                <td>
                    <table width="300" border="0" cellpadding="0" cellspacing="0">
                    <tr>
                        <td width="130" align="right">Password:</td>
                        <td width="7"></td>
                        <td align="right">
                        <label><input name="UserPass" type="password" id="UserPass" class="textInputField" size="25" autocomplete="off" /></label>
                        </td>
                    </tr>
                    </table>
                </td>
                </tr>
    
        
                <tr id="trPasswordExpiredNoChange" style="display:none" >
                <td>
                    <table>
                    <tr>
                        <td height="20">&#160;</td>
                    </tr>
                    <tr>
                        <td><span class="wrng">Your password is expired. Please contact your administrator for assistance.</span></td>
                    </tr>
                    </table>
                </td>
                </tr>
                   
        
                <tr id="trPasswordExpired" style="display:none" >
                <td>
                    <table>
                    <tr>
                        <td height="20">&#160;</td>
                    </tr>
                    <tr>
                        <td><span class="wrng">Your password is expired. Click <a id = "passwordchangelink" href="password.aspx">here</a> to change it.</span></td>
                    </tr>
                    </table>
                </td>
                </tr>
    
        
                <tr id="trErrorWorkSpaceInUse" style="display:none" >
                <td>
                    <table>
                    <tr>
                        <td height="20">&#160;</td>
                    </tr>
                    <tr>
                        <td><span class="wrng">Another user of your computer is currently using this connection.  This user must disconnect before you can log on.</span></td>
                    </tr>
                    </table>
                </td>
                </tr>
    
        
                <tr id="trErrorWorkSpaceDisconnected" style="display:none" >
                <td>
                    <table>
                    <tr>
                        <td height="20">&#160;</td>
                    </tr>
                    <tr>
                        <td><span class="wrng">Another user of your computer has disconnected from this connection.  Please type your user name and password again.</span></td>
                    </tr>
                    </table>
                </td>
                </tr>
    
        
                <tr id="trErrorIncorrectCredentials" style="display:none" >
                <td>
                    <table>
                    <tr>
                        <td height="20">&#160;</td>
                    </tr>
                    <tr>
                        <td><span class="wrng">The user name or password that you entered is not valid. Try typing it again.</span></td>
                    </tr>
                    </table>
                </td>
                </tr>
    
                <tr id="trErrorDomainNameMissing" style="display:none" >
                <td>
                    <table>
                    <tr>
                        <td height="20">&#160;</td>
                    </tr>
                    <tr>
                        <td><span class="wrng">You must enter a valid domain name.</span></td>
                    </tr>
                    </table>
                </td>
                </tr> 
    
        
                <tr id="trErrorUnauthorizedAccess" style="display:none" >
                <td>
                    <table>
                    <tr>
                        <td height="20">&#160;</td>
                    </tr>
                    <tr>
                        <td><span class="wrng">You aren't authorized to log on to this connection.  Contact your system administrator for authorization.</span></td>
                    </tr>
                    </table>
                </td>
                </tr>
    
        
                <tr id="trErrorServerConfigChanged" style="display:none" >
                <td>
                    <table>
                    <tr>
                        <td height="20">&#160;</td>
                    </tr>
                    <tr>
                        <td><span class="wrng">Your RD Web Access session expired due to configuration changes on the remote computer.  Please sign in again.</span></td>
                    </tr>
                    </table>
                </td>
                </tr>
    
                <tr id="trErrorGenericClaimsAuthFailure" style="display:none" >
                <td>
                    <table>
                    <tr>
                        <td height="20">&#160;</td>
                    </tr>
                    <tr>
                        <td><span class="wrng">We can't sign you in right now. Please try again later.</span></td>
                    </tr>
                    </table>
                </td>
                </tr> 
    
                <tr>
                <td height="20">&#160;</td>
                </tr>
                <tr>
                <td height="1" bgcolor="#CCCCCC"></td>
                </tr>
                <tr>
                <td height="20">&#160;</td>
                </tr>
    
                <tr>
                <td>
                    <table border="0" cellspacing="0" cellpadding="0">
                    <tr>
                        <td>Security&#160;<span id="spanToggleSecExplanation" style="display:none">(<a href="javascript:onclickExplanation('lnkShwSec')" id="lnkShwSec">show explanation</a><a href="javascript:onclickExplanation('lnkHdSec')" id="lnkHdSec" style="display:none">hide explanation</a>)</span></td>
                    </tr>
                    </table>
                </td>
                </tr>
                <tr>
                <td height="5"></td>
                </tr>
    
                <tr>
                <td>
                    <table border="0" cellspacing="0" cellpadding="0" style="display:none" id="tablePublicOption" >
                    <tr>
                        <td width="30">
                        <label><input id="rdoPblc" type="radio" name="MachineType" value="public" class="rdo" onclick="onClickSecurity()" /></label>
                        </td>
                        <td>This is a public or shared computer</td>
                    </tr>
                    <tr id="trPubExp" style="display:none" >
                        <td width="30"></td>
                        <td><span class="expl">Select this option if you use RD Web Access on a public computer.  Be sure to log off when you have finished using RD Web Access and close all windows to end your session.</span></td>
                    </tr>
                    <tr>
                        <td height="7"></td>
                    </tr>
                    </table>
                </td>
                </tr>
    
                <tr>
                <td>
                    <table border="0" cellspacing="0" cellpadding="0" style="display:none" id="tablePrivateOption" >
                    <tr>
                        <td width="30">
                        <label><input id="rdoPrvt" type="radio" name="MachineType" value="private" class="rdo" onclick="onClickSecurity()" checked="checked" /></label>
                        </td>
                        <td>This is a private computer</td>
                    </tr>
                    <tr id="trPrvtExp" style="display:none" >
                        <td width="30"></td>
                        <td><span class="expl">Select this option if you are the only person who uses this computer.  Your server will allow a longer period of inactivity before logging you off.</span></td>
                    </tr>
                    <tr>
                        <td height="7"></td>
                    </tr>
                    </table>
                </td>
                </tr>
    
                <tr>
                <td>
                    <table border="0" cellspacing="0" cellpadding="0">
                    <tr id="trPrvtWrn" style="display:none" >
                        <td width="30"></td>
                        <td><span class="wrng">Warning:  By selecting this option, you confirm that this computer complies with your organization's security policy.</span></td>
                    </tr>
                    </table>
                </td>
                </tr>
    
                <tr>
                <td>
                    <table border="0" cellspacing="0" cellpadding="0">
                    <tr id="trPrvtWrnNoAx" style="display:none">
                        <td><span class="wrng">Warning:  By logging in to this web page, you confirm that this computer complies with your organization's security policy.</span></td>
                    </tr>
                    </table>
                </td>
                </tr>
    
                <tr>
                <td height="20">&#160;</td>
                </tr>
    
                <tr>
                <td height="20">&#160;</td>
                </tr>
                <tr>
                <td align="right"><label><input type="submit" class="formButton" id="btnSignIn" value="Sign in" /></label>
                </td>
                </tr>
    
                <tr>
                <td height="20">&#160;</td>
                </tr>
                <tr>
                <td height="1" bgcolor="#CCCCCC"></td>
                </tr>
    
                <tr>
                <td height="20">&#160;</td>
                </tr>
                <tr>
                <td>To protect against unauthorized access, your RD Web Access session will automatically time out after a period of inactivity.  If your session ends, refresh your browser and sign in again.</td>
                </tr>
    
                <tr>
                <td height="30">&#160;</td>
                </tr>
    
            </table>
    
          </form>



    ------------------------------
    Michael
    ------------------------------



  • 10.  RE: Forms based SSO - credential pass-through

    Posted Fri November 23, 2018 02:30 PM
    Hi Michael,

    OK, I was determined to figure this out so I installed RDWeb myself and did my own debug.

    In the end it turns out the issue is that the RDWeb Login Page URL and the Action URL are the same (both login.aspx).  This means that WebSEAL always matches the page as a login page and so never gets to matching it as a page that might contain credentials to learn.

    To fix this I had to make a change to the login.aspx of the RDWeb application.  It's easy to do because it's just a file you can edit.

    I added a dummy GO=1 attribute to the URL used to POST.  This is ignored by the application but gives me something that can differentiate the login page from the POST:

    strReturnUrlPage = objQueryString["ReturnUrl"];
    strReturnUrl = "?GO=1&ReturnUrl=" + strReturnUrlPage;
    if ( strReturnUrlPage.Equals("default.aspx", StringComparison.CurrentCultureIgnoreCase) == true &&
    objQueryString["p"] != null && objQueryString["p"] == "c"
    )
    {
       strReturnUrlPage = "config.aspx";
       strReturnUrl = "?GO=1&ReturnUrl=" + strReturnUrlPage;
    }

    My fsso.conf file is as follows:

    [forms-sso-login-pages]
    login-page-stanza = login-page-one
    login-credential-learning = yes

    [login-page-one]
    login-page = /RDWeb/Pages/en-US/login.aspx?Return*
    login-form-response-pattern = *FrmLogin*
    login-form-action = *login.aspx*
    #default-login-form-action =

    gso-resource = rdweb
    argument-stanza = args-for-login-page-one
    login-success-pattern = -200 +302

    [args-for-login-page-one]
    DomainUserName = gso:username
    UserPass = gso:password

    Be aware that my gso-resource is different from yours (if you want to cut and paste).

    This setup works because when login POST is sent, it has format:
    login.aspx?GO=1&ReturnURL=xxxx
    This doesn't match login.aspx?Return* and so it doesn't match as a login page and so it is matched as a login action and the learning is triggered.

    I hope this helps.

    Cheers... Jon.

    ------------------------------
    Jon Harry
    Consulting IT Security Specialist
    IBM
    ------------------------------



  • 11.  RE: Forms based SSO - credential pass-through

    Posted Fri November 23, 2018 02:38 PM
    One thing that just occurred to me...

    Given that this is a Windows application sitting behind IIS, would it not be easier to enable your WebSEAL for delegated Kerberos authentication rather than relying on form-filling?

    Jon.

    ------------------------------
    Jon Harry
    Consulting IT Security Specialist
    IBM
    ------------------------------



  • 12.  RE: Forms based SSO - credential pass-through

    Posted Sat November 24, 2018 08:24 AM
    Hi Jon,

    Thank you very much for your efforts! I have to sync with another team for making changes to RDS, but given the limited impact I assume that will not be an issue.

    Concerning the move to Kerberos, that’s probably the better move to make. However I wanted to use RDS as a quick proof of concept regarding the forms based so capabilities and limitations. I guess they are clear now ;).




  • 13.  RE: Forms based SSO - credential pass-through

    Posted Tue December 18, 2018 12:59 PM
    Edited by Michael Boey***** Tue December 18, 2018 12:59 PM
    Update:
    I implemented the Store password in GSO at login time (v2) option.
    Since this was my first real encounter with ISAM it took me some time, but actually it is pretty easy (and I had some help of Peter). 

    Basically the steps were the following:
    - Create a custom U/P mechanism-mapping where the UP is stored in idmappingextcache for a limited amount of time
    - Use that U/P mechanism by default (or for RDS only)
    - Create a mapping which will respond to GSO get requests and retrieve gso-password and gso-username from the idmappingextcache
    - Configure FSSO for using the GSO service

    gso-resource = [url]*****.com:443,mga/sps/apiauthsvc/policy/gsoservice?username= 

    If anyone wants more details, please ask.
    Thanks for all the help!




    ------------------------------
    Michael
    ------------------------------



  • 14.  RE: Forms based SSO - credential pass-through

    Posted Tue December 18, 2018 02:03 PM
    Hi Michael,

    I am certainly interested in the detail.  This would make a great subject for a blog post if you're willing to share the code snippets.  I'm sure you are not the only one who has be looking into this but you are the first I know of to set up a GSO service in the Authentication Service!

    Nice work.

    Jon.

    ------------------------------
    Jon Harry
    Consulting IT Security Specialist
    IBM
    ------------------------------



  • 15.  RE: Forms based SSO - credential pass-through

    Posted Wed December 19, 2018 11:42 AM
    ​Hi Jon,

    I'm certainly willing to share code snippets. I have them available but need to take some time to present them more nicely here. I should have some time by the latest next week. Please ping me in case I forgot!

    Kr,
    Michael

    ------------------------------
    Michael
    ------------------------------



  • 16.  RE: Forms based SSO - credential pass-through

    Posted Thu December 20, 2018 03:27 AM
    Edited by Michael Boey***** Thu December 20, 2018 03:29 AM
    ​Some details:
    Credits to Peter Volckaert and https://philipnye.com . Most of what I did was copy pasting things together.
    Disclaimer:
    This was done as part of a PoC and is not running in production. Several improvements might be possible, such as encryption of the password in idmappingextcache. Note that the GSO service provides obfuscation out of the box, but therefore you'd need to use both PUT and GET of that service. In this implementation, we are manually putting the password in idmappingextcache, since this has the advantage of being able to control its lifetime.
    Also note that perhaps some steps are not required. It's just a summary of what we did.

    Please reply to this thread in case you make improvements.
    It's possible that I'm not always using the right terminology. Feel free to correct me.

    Overview:
    • Prep
    • Create custom U/P service to store the U/P in the idmappingextcache upon logging in
    • Configure that U/P policy by default (optional)
    • Create GSO webservice which will respond to GSO get queries and take the information out of the idmappingextcache
    • Configure the FSSO mechanism to use that GSO service
    • Set permissions

    Prep
    • sps.httpRequrestClaims.enabled must be set to true
    • sps.httpRequestClaims.filterSpec must be set to cookies=*: headers=*: parameters=*
    • I'll be using the runtime configuration for the custom U/P mechanism (https://philipnye.com/2017/06/14/isam-infomap-any-alias-authentication/)  so make sure you have admin credentials configured in the bind-credentials stanza in ldap.conf
    • sps.authService.policyKickoffMethod is set to 'path'
    • upgrade to 9.0.6, this relaxes the requirement to have application/json headers present. Otherwise you'll have to inject an accept header yourself. (https://www-01.ibm.com/support/docview.wss?uid=ibm10734111&aid=1)

    Custom U/P service
    The mapping rule is of course the most important part, since we'll be adding the username-password to the idmappingextcache.
    importClass(Packages.com.ibm.security.access.user.UserLookupHelper);
    importClass(Packages.com.tivoli.am.fim.trustserver.sts.utilities.IDMappingExtUtils);
    
    // Get username and password from what the user submitted in the form.
    
    var username = context.get(Scope.REQUEST, "urn:ibm:security:asf:request:parameter", "username");
    var password = context.get(Scope.REQUEST, "urn:ibm:security:asf:request:parameter", "password");
    validateCredentials();
    
    function validateCredentials() {
    	// Authenticate the user by verifying the username & password	
    	// Use the AAC Username/Password mechanism setting to init the helper: so set to init(true)
    	if(username == null || password == null) {
    	  //This is likely the first time through
    	  //Display the default template page here -
    	  //to challenge for the username and password
    	success.setValue(false);
    	} else {
    	var userLookupHelper = new UserLookupHelper();
        //set false to use the runtime component default connection
    	userLookupHelper.init(false);
    	if(userLookupHelper.isReady()) {		
    		var user = userLookupHelper.getUser(username);
    		if(user != null) {
    			isAuthenticated = user.authenticate(password);
    			if (isAuthenticated) {
    				//keep it for 600 seconds in cache. 
    				//this may be improved by using session validity time, if possible?
    				IDMappingExtUtils.getIDMappingExtCache().put(username, username, 600);
    				IDMappingExtUtils.getIDMappingExtCache().put(username + "-pass", password, 600);
    				context.set(Scope.SESSION, "urn:ibm:security:asf:response:token:attributes", "username", username);
    				success.setValue(true);
    
    			} else {
    				macros.put("@ERROR_MESSAGE2@","Invalid credentials");
    				success.setValue(false);
    
    			}
    		} else {
    			macros.put("@ERROR_MESSAGE3@","User null");
    			success.setValue(false);
    
    		} 
    	}else {
    			macros.put("@ERROR_MESSAGE4@","Lookup Helper not ready");
    			success.setValue(false);
    
                    }
    }
    }


    Then, create a mechanism linking this mapping rule to a template (you can use the default login.html).
    Finally, create a policy with this mechanism as a workflow step.

    Configure that U/P policy by default (optional)
    Follow https://philipnye.com/2015/12/22/isam-selective-use-of-local-response-redirect/ to configure this new U/P policy by default.

    Create GSO webservice which will respond to GSO get queries and take the information out of the idmappingextcache
    The most important part is again the mapping rule:
    importClass(Packages.com.tivoli.am.fim.trustserver.sts.utilities.IDMappingExtUtils);
    importClass(Packages.com.tivoli.am.fim.trustserver.sts.utilities.IDMappingExtCacheDMAPImpl);
    
    
    //Credentials are stored in the idmappingextcache through the custom u/p mechanism (upidmapping...)
    //start with null
    var gsousername = "";
    var gsopassword = "";
    
    
    //Get username
    var username = context.get(Scope.REQUEST, "urn:ibm:security:asf:request:parameter", "username");
    //GSO call adds a forward slash
    usernamenoslash = username.substr(1)
    if (usernamenoslash != null) {
      gsousername = "some-domain\\\\" + IDMappingExtUtils.getIDMappingExtCache().get(usernamenoslash);
      gsopassword= IDMappingExtUtils.getIDMappingExtCache().get(usernamenoslash + "-pass");
    }
    
    // we never actually perform a login with this infomap
    success.setValue(false);
    
    /*
     * Now return the page 
     */
    page.setValue("/authsvc/authenticator/gsoresponder/gso.html");
    //macros.put("@AUTHENTICATED@", ''+(username != null));
    //macros.put("@USERNAME@", (username != null ? htmlEncode(username) : ""));
    //Should we consider injection attacks?
    macros.put("@GSO_USERNAME@", (gsousername!= null ? gsousername : ""));
    macros.put("@GSO_PASSWORD@", (gsopassword!= null ? gsopassword : ""));
    Create the mechanism, make sure to add a gso.json file (we'll not be using the html version). Our json looks as follows:
    { "gso-username": "@GSO_USERNAME@", "gso-password": "@GSO_PASSWORD@" , "error": "@ERROR_MESSAGE@" }
    And again, create a policy with the GSO mechanism as a workflow step.

    Configure the FSSO mechanism to use that GSO service
    [forms-sso-login-pages]
    login-page-stanza = login-page-one
    
    
    [login-page-one]
    login-page = /RDWeb/Pages/en-US/login.aspx*
    login-form-action = *
    login-success-pattern = +302
    gso-resource = [url]****redacted****:443,mga/sps/apiauthsvc/policy/gsoservice?username= 
    argument-stanza = args-for-login-page-one
    
    [args-for-login-page-one]
    DomainUserName = gso:username
    UserPass = gso:password​

    Set permissions on the gso service
    I'll leave that one up to the reader. We created a PoP blocking access to the GSOService for any network (and therefore implicitly only allowing access to the service from ISAM).




    ------------------------------
    Michael
    ------------------------------



  • 17.  RE: Forms based SSO - credential pass-through

    Posted Thu December 20, 2018 08:31 AM
    Michael,

    Thank you for taking the time to write this up.  It's very interesting to see the ideas all put together.

    Cheers... Jon.

    ------------------------------
    Jon Harry
    Consulting IT Security Specialist
    IBM
    ------------------------------