cancel
Showing results for 
Search instead for 
Did you mean: 
cancel
Showing results for 
Search instead for 
Did you mean: 

Community Tip - Visit the PTCooler (the community lounge) to get to know your fellow community members and check out some of Dale's Friday Humor posts! X

Configuring SAML SSO with Reverse Proxy

avillanueva
22-Sapphire II

Configuring SAML SSO with Reverse Proxy

Version: Windchill 12.0

 

Use Case: I have a slightly advanced setup of a reverse proxy handling SSL https and the external facing hostname for users and the internal PTC Apache server configured with HTTP and a virtual hostname known only on that server (not in DNS) . The shibboleth metadata file that was generated exposes that internal virtual hostname and my IDP requires reply and login urls to be https. Where did I good this?


Description:

@jbailey you might know this off the top of your head. 

For discussions sake, say my system DNS addressable host is pdmlink-test.mycompany.com and the internal name is pdm12.mycompany.com. I've installed shibboleth to my windchill server, configured it, defined an entityID that is "https://pdmlink-test.my company.com/shibboleth" and it is talking to my IDP. We got an error from the IDP when login was redirected that the replyURL did not match. Checking the metadata file, all the location attributes are showing "http://pdm12.mycompany.com/Shibboleth.sso/..." yada yada. Am I correct is saying that this should have said https://pdmlink-test.mycompany.com...?

Did Shibboleth need to be configured on my reverse proxy webserver? I have that module installed on my PTC Apache server which is behind the proxy. 

1 ACCEPTED SOLUTION

Accepted Solutions
avillanueva
22-Sapphire II
(To:avillanueva)

I justed wanted to return to this thread and close it out thought I still have a few more loose ends to wrap up. Thank you so much to @jbailey for all your help. We actually took this offline to keep thread smaller. Here is a summary of what I learned:

  • Metadata file must reference your proxy so that should be the domain you present to IDP.
  • bindingTemplate.html CAN be copied from PTC codebase so long as you are not doing anything fancy. Documentation has wrong location. Its in the codebase/templates folder not WEB-INF. 
  • PTC HttpServer ServerName needed to match the proxy domain. This is what seemed to influence what shibboleth used in generating the Metadata file. I also received 404 errors getting the Metadata file when it did not match.
  • I still have issues with the sessionHook.jsp for which I have a PTC ticket on. Take note of this debug logger (sso.shibboleth.sessionHook). This was key to it complaining about the different domains. I was able to code around the issue but intend to return to OOTB hook. For now, its working as it should. I will try and collect my notes and write up something clearer.

View solution in original post

20 REPLIES 20

Your IdP shouldn't need to know (or expose) anything for the local host.  entityID is just a string that matches the IdP. 

 

"Checking the metadata file, all the location attributes are showing "http://pdm12.mycompany.com/Shibboleth.sso/..." yada yada. Am I correct is saying that this should have said https://pdmlink-test.mycompany.com...?"

  • Yes, or maybe... You can either use a full address for handlerURL="https://pdmlink-test.mycompany.com/Shibboleth.sso" or a relative address like handlerURL="/Shibboleth.sso.
  • Interestingly enough in my main Session - I used the full URL - and in my reauthsecure ApplicationOverride (needed for electronic signatures) I used a relative URL handlerURL="/reauthsecure/Shibboleth.sso 

Shibboleth shouldn't be installed at the proxy level- because then you would have to configure Windchill Apache to accept the username in the header from the proxy which could be impersonated (PTC recommends against this method anyway).

 

If your IdP is configured with FQDN's instead of relative paths for the Assertion Consumer Service URL's, make sure they are for the proxy FQDN, not the internal host name.  Ideally you could just use relative URL's

jbailey_0-1720543430141.png

 

 

Also, I would consider end to end HTTPS. Yes, it is another cert and probably a little bit of a performance hit in transactions, but you will end up more secure.

avillanueva
22-Sapphire II
(To:jbailey)

Agreed on more secure but this setup makes cloning and other things easier. Recommended by consultants. We've also changed company names so many darn times, its nice to be able to change it in a few locations (on the proxy and some xconf file).

avillanueva
22-Sapphire II
(To:avillanueva)

Here is some testing of configurations info. My IDP has return URL as "https://pdmlink-test.mycompany.com..." pattern. With the configuration below:

<Sessions lifetime="28800" timeout="3600" relayState="ss:mem"
                  checkAddress="false" handlerSSL="false" cookieProps="https"
                  redirectLimit="exact" >

yields a urlMismatchError from the IDP since it was being given "http://pdm12.mycompany.com..." as the URL. I can confirm that the metadata file indeed does show pdm12 as hostname and I can download it using https://pdmlink-test.mycompany.com/Shibboleth.sso/Metadata 

In an attempt to fix this I modified the above configuration to the following:

<Sessions lifetime="28800" timeout="3600" relayState="ss:mem"
                  checkAddress="false" handlerSSL="false" cookieProps="https"
                  redirectLimit="exact" handlerURL="https://pdmlink-test.mycompany.com/Shibboleth.sso">

 Now my IDP redirects me to https://pdmlink-test.mycompany.com/Shibboleth.sso/SAML2/POST but I now get a 404 error. It seems that the IDP liked what it got but something went wrong between the proxy and the main webserver. I can see in the webserver access log the 404 message. Getting closer. Any clue where to look next? I think it might be the Shibboleth module configuration on the Windchill webserver.

Download the SAML Tracer extension for Chrome or Edge and redo the auth attempt from a clean session with SAML tracer open. It will help you figure out what isn't liked (if it is SP side or IdP side).

 

Is the proxy new for you?  (just going through my proxy notes, not assuming you missed any of this 🙂

 

Did you set wt.server.codebase="$(wt.webserver.protocol)://<PROXY FQDN>:$(wt.webserver.port)/$(wt.webapp.name)" -t codebase/wt.properties -p ?

 

Something else you might try in your proxy conf file is to add ProxyPass and ProxyPassReverse for the SSO related paths ( I don't know if this is necessary or not but you could do it to force to the right local address)

 

ProxyPass /Shibboleth.sso https://<LOCAL WC SERVER FQDN>:443/Shibboleth.sso
ProxyPassReverse /Shibboleth.sso https://<LOCAL WC SERVER FQDN>:443/Shibboleth.sso
ProxyPass /secure https://<LOCAL WC SERVER FQDN>:443/secure
ProxyPassReverse /secure https://<LOCAL WC SERVER FQDN>:443/secure
ProxyPass /reauthsecure https://<LOCAL WC SERVER FQDN>:443/reauthsecure
ProxyPassReverse /reauthsecure https://<LOCAL WC SERVER FQDN>:443/reauthsecure
avillanueva
22-Sapphire II
(To:jbailey)

No proxy is not new. I've been running it for years. Here is my proxy config:

# Windchill Reverse Proxy Additions and Settings
RewriteEngine on
SSLProxyEngine on
ProxyPass /Windchill/ http://pdm12.mycompany.com:8888/Windchill/
ProxyPassReverse /Windchill/ http://pdm12.mycompany.com:8888/Windchill/
ProxyPass /Windchill-WHC http://pdm12.mycompany.com:8888/Windchill-WHC
ProxyPassReverse /Windchill-WHC http://pdm12.mycompany.com:8888/Windchill-WHC
ProxyPass /Windchill-WHC/ http://pdm12.mycompany.com:8888/Windchill-WHC/
ProxyPassReverse /Windchill-WHC/ http://pdm12.mycompany.com:8888/Windchill-WHC/
RewriteRule ^/Windchill$ /Windchill/ [R]

#Shibboleth Reverse Proxy Additions and Settings
ProxyPass        /Shibboleth.sso/ http://pdm12.mycompany.com:8888/Shibboleth.sso/
ProxyPassReverse /Shibboleth.sso/ http://pdm12.mycompany.com:8888/Shibboleth.sso/

#Basic Authentication login page settings
ProxyPass        /basicLogin.html http://pdm12.mycompany.coml:8888/basicLogin.html
ProxyPassReverse /bsaicLogin.html http://pdm12.mycompany.com:8888/basicLogin.html

# Force requests to Windchill
RedirectMatch ^/$ https://pdmlink-test.mycompany.com/Windchill/
RedirectMatch ^/windchill$ https://pdmlink-test.mycompany.com/Windchill/

What was added was the Shibboleth and basic auth sections. The other proxy settings I've always had. I can see that its hitting the pdm12 webserver since its logs the URL and a 404 error. This is why I suspect Shibboleth module is throwing the error. 

avillanueva
22-Sapphire II
(To:avillanueva)

skype-mad.gif

welp, my issue was a misconfigured webserver all along. I came across a testy thread online that indicated my ServerName value was wrong. It was set to pdm12.my company.com:80 and should have been the same as my proxy as https://pdmlink-test.mycompany.com:443. That fixed my 404 error on the Metadata and I think I am authenticating. The remaining issue has to do with the sessionHook step.

Request Id:	4eih2vlk;lyeu3nzi;3457257;ceciz6;1828
Request URI:	/Windchill/sso/shibboleth/sessionHook
Query String:	<redacted>
Status Code:	500
Exception:	wt.util.WTException: Failed to process the request. Contact your administrator for assistance.

rechecking my steps but stumped on this one.

I always forget about that one:-)

 

Modify <wthome>codebase\WEB-INF\jsp\sso\shibboleth\sessionHook.jsp (Had to do this for certain older browsers - may not be needed in your environment) to add
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
To line 59
 
Modify Web.xml, Config.xml, & webAppAJPConf.template for Sessionhook/sso
Edit web.xml located at $WT_HOME/codebase/WEB-INF
Add the new entry in MVCDispatcher <servlet-mapping> for /sso/* URL, such as /ptc1/* and /app/*.
For example,
 
<servlet-mapping>
<servlet-name>MVCDispatcher</servlet-name>
<url-pattern>/sso/*</url-pattern>
</servlet-mapping>
Edit config.xml located at $WT_HOME/tomcat 
Add the new entry in <target name="-addTargetedUriWorkerMapEntries"> for /sso/* URL , such as /ptc1/* and /app/*.
For example,
<target name="-addTargetedUriWorkerMapEntries">
<echo file="${uriworkerFile}" append="true" message="/${appName}/sso/*=${iisAjpWorker}${line.separator}"/>
</target>
 
 
Add an entry to 30-app-Windchill-AJP.conf for /sso/* URL, just like entries available for /ptc1 and /app URL
Edit <http_server_directory>\conf\templates\webapp\webAppAJPConf.template and add the following
JkMount /@@WEB_APP_NAME@@/sso/* @@AJP_WORKER_NAME@@

 

avillanueva
22-Sapphire II
(To:jbailey)

Let's step through this (I think I did all of this):

1. sessionHook.jsp (this was not done but based on error, do not think its the issue)

2. web.xml

<servlet-mapping>
    <servlet-name>MVCDispatcher</servlet-name>
    <url-pattern>/servlet/WizardServlet/*</url-pattern>
    <url-pattern>/servlet/ActionsMenu/*</url-pattern>
    <url-pattern>/servlet/RecentList/*</url-pattern>
    <url-pattern>/servlet/Navigation/*</url-pattern>
    <url-pattern>/servlet/SuggestServlet/*</url-pattern>
    <url-pattern>/servlet/TypeBasedIncludeServlet/*</url-pattern>
    <url-pattern>/servlet/UIValidationAJAXServlet/*</url-pattern>
    <url-pattern>/ptc1/*</url-pattern>
    <url-pattern>/app/</url-pattern>
    <url-pattern>/gwt/*</url-pattern>
    <url-pattern>/sso/*</url-pattern>
  </servlet-mapping>

3. config.xml

 <target name="-addTargetedUriWorkerMapEntries">
    <!-- Description: Adds specific uriworkermap.properties entries required by a Windchill web app -->
    <echo file="${uriworkerFile}" append="true" message="/${appName}/*.jsp=${iisAjpWorker}${line.separator}"/>
    <echo file="${uriworkerFile}" append="true" message="/${appName}/*.jspx=${iisAjpWorker}${line.separator}"/>
    <echo file="${uriworkerFile}" append="true" message="/${appName}/*.jspf=${iisAjpWorker}${line.separator}"/>
    <echo file="${uriworkerFile}" append="true" message="/${appName}/*.jsp*=${iisAjpWorker}${line.separator}"/>
    <echo file="${uriworkerFile}" append="true" message="/${appName}/servlet/*=${iisAjpWorker}${line.separator}"/>
    <echo file="${uriworkerFile}" append="true" message="/${appName}/j_security_check=${iisAjpWorker}${line.separator}"/>
    <echo file="${uriworkerFile}" append="true" message="/${appName}/*/j_security_check=${iisAjpWorker}${line.separator}"/>
    <echo file="${uriworkerFile}" append="true" message="/${appName}/*.jar=${iisAjpWorker}${line.separator}"/>
    <echo file="${uriworkerFile}" append="true" message="/${appName}/gwt/servlet/*=${iisAjpWorker}${line.separator}"/>
    <echo file="${uriworkerFile}" append="true" message="/${appName}/gwt/*/servlet/*=${iisAjpWorker}${line.separator}"/>
    <echo file="${uriworkerFile}" append="true" message="/${appName}/ptc1/*=${iisAjpWorker}${line.separator}"/>
    <echo file="${uriworkerFile}" append="true" message="/${appName}/app=${iisAjpWorker}${line.separator}"/>
    <echo file="${uriworkerFile}" append="true" message="/${appName}/app/*=${iisAjpWorker}${line.separator}"/>
    <echo file="${uriworkerFile}" append="true" message="/${appName}/oslc/*=${iisAjpWorker}${line.separator}"/>
    <echo file="${uriworkerFile}" append="true" message="/${appName}/trustedAuth/*=${iisAjpWorker}${line.separator}"/>
    <echo file="${uriworkerFile}" append="true" message="/${appName}/protocolAuth/*=${iisAjpWorker}${line.separator}"/>
    <echo file="${uriworkerFile}" append="true" message="/${appName}/sslClientAuth/*=${iisAjpWorker}${line.separator}"/>
    <echo file="${uriworkerFile}" append="true" message="/${appName}/wt.properties=${iisAjpWorker}${line.separator}"/>
    <echo file="${uriworkerFile}" append="true" message="/${appName}/*/wt.properties=${iisAjpWorker}${line.separator}"/>
    <echo file="${uriworkerFile}" append="true" message="/${appName}/MethodServer=${iisAjpWorker}${line.separator}"/>
    <echo file="${uriworkerFile}" append="true" message="/${appName}/jwt/*=${iisAjpWorker}${line.separator}"/>
    <echo file="${uriworkerFile}" append="true" message="/${appName}/TokenGenerator/*=${iisAjpWorker}${line.separator}"/>
    <echo file="${uriworkerFile}" append="true" message="/${appName}/sso/*=${iisAjpWorker}${line.separator}"/>
  </target>

4. 30-app-Windchill-AJP.conf

JkMount /Windchill/WebEditor/* ajpWorker
  JkMount /Windchill/MethodServer ajpWorker
  JkMount /Windchill/jwt/* ajpWorker
  JkMount /Windchill/TokenGenerator/* ajpWorker
  JkMount /Windchill/sso/* ajpWorker
</IfModule>

I did restart and did clear tomcat cache. I think this is correct entries. 

Have you done the SAML trace yet? that gives you a pretty good indication if the error lies on the IdP side or the SP side.

 

What attribute is defined in "REMOTE_USER" in the ApplicationDefault segment? Is that attribute defined in attributemap.xml? Is the attribute being sent by the IdP matching the attribute name (case sensitive) defined in REMOTE_USER / attributemap.xml?

avillanueva
22-Sapphire II
(To:jbailey)

I think I am getting as far as step 7 and failing at 8. 

avillanueva_1-1720612007063.png

Yes, was able run trace:

avillanueva_2-1720612125223.png

Under the SAML tab for the last POST, I can see all my information as attributes. We've used sAMAccountName in our AD mapping for ever which I have plans to change but that is what matches to my Windchill ID. 

<Attribute Name="http://schemas.xmlsoap.org/ws/2005/05/identity/claims/givenname">
                <AttributeValue>Antonio</AttributeValue>
            </Attribute>
            <Attribute Name="http://schemas.xmlsoap.org/ws/2005/05/identity/claims/surname">
                <AttributeValue>Villanueva</AttributeValue>
            </Attribute>
            <Attribute Name="http://schemas.xmlsoap.org/ws/2005/05/identity/claims/emailaddress">
                <AttributeValue>myemail</AttributeValue>
            </Attribute>
            <Attribute Name="http://schemas.xmlsoap.org/ws/2005/05/identity/claims/name">
                <AttributeValue>my_sAMAccount_id</AttributeValue>
            </Attribute>

Remote user is as follows: REMOTE_USER="uid"

and attribute-map.xml is as follows:

<!-- Added based on CS387845 -->
    <Attribute name="http://schemas.xmlsoap.org/ws/2005/05/identity/claims/sAMAccountName" id="uid">
        <AttributeDecoder xsi:type="StringAttributeDecoder" caseSensitive="false"/>
    </Attribute>

Hmm, I think I see a disconnect from CS387845. Possibly, should I be mapping to "name"? Odd since when I am currently authenticating to AD, I used sAMAccountName,

You are on the right track questioning "name" yes that is likely the issue. 

 

Try this in attribute map:

<!-- Added based on CS387845 -->
    <Attribute name="http://schemas.xmlsoap.org/ws/2005/05/identity/claims/name" id="uid">
        <AttributeDecoder xsi:type="StringAttributeDecoder" caseSensitive="false"/>
    </Attribute>

 

After that, restart apache and shibboleth service and try again

avillanueva
22-Sapphire II
(To:jbailey)

I did a bit more digging in the knowledge base and its strange. BTW, I was successfully able to authenticate and Windchill came up. I did change it to name but it did not work, got the same error. I believe name is the right value based on the SAML trace. Thanks for that. I came across CS387849 which says you can just remove the session hook. I did that and bingo, I am in. 

Reading further, I questioned what is the session hook even for? CS349078 indicates it was a fix in cases where # in the URL caused issues and I am running 12.0.2. So strange. CS415010 was the exact error I was seeing which strongly points to the attribute mapping being the cause however, since I changed it from sAMAccountName to name, that should have fixed it.

    <Attribute name="http://schemas.xmlsoap.org/ws/2005/05/identity/claims/name" id="uid">
        <AttributeDecoder xsi:type="StringAttributeDecoder" caseSensitive="false"/>
    </Attribute>

Sessionhook is required. Otherwise whenever you send someone a link that has the # sign in it, it will take them to the home page instead.

 

Your users will hate you quick if Windchill behaves this way..

jbailey_0-1720616032007.png

 

avillanueva
22-Sapphire II
(To:jbailey)

Yep, did a test with "Email this page". I hate myself already.

I would add sessionhook back to Shibboleth2.xml

 

Make sure in the SSO Block to add postArtifact / template / outgoingbindings (the bindingTemplate.html callout and file mods are what Windchill uses to make sessionhook work, so this is important!)

 

 

 

<SSO entityID="<IdP Entity>" 
....

postArtifact="true" template="bindingTemplate.html" outgoingBindings="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST" >

....

            </SSO>

 

 

 

 

Make sure to edit the bindingTemplate.html file located at shibboleth_install_directory/etc/shibboleth (Add the following after the </head> tag and before the <noscript> tag

 

 

 

 

<!-- PTC Recommended Customization(1) Start  -->
<!-- SHA-256 encoding for 'bindingTemplate.html' is a891be6b892aae62a98c82206444295c252c16622c1a386c5b0fbc293e376745  -->
<!-- keep the content, needed to handle some use cases -->
<body onload="submit();">
<!-- PTC Recommended Customization(1) End  -->

<script type="text/javascript">
    <!--
    document.write("<p>You are automatically being redirected to the authentication service. ");
    document.write("If the browser appears to be hung up after 15-20 seconds, try reloading ");
    document.write("the page before contacting the technical support staff in charge of the ");
    document.write("authentication service you are trying to access.</p>");
    document.write("<h2>Redirecting...</h2>");
    // -->
    <!-- PTC Recommended Customization(2) Start  -->
    if (document.body != null && typeof document.body.onload !== 'function' && window.location != null) {
        window.location.reload();
    }
    <!-- PTC Recommended Customization(2) End  -->
</script>

<!-- PTC Recommended Customization(3) Start  -->
<script type="text/javascript">
    /**
     * Saves the URL fragment to session store, if it is available in browsers address bar
     */
    function saveURLFragment(){
        var URL_FRAGMENT_KEY = 'WINDCHILL_SSO_URL_FRAGMENT';
        var windchillStore = window.sessionStorage;
        if(windchillStore){
            var hash = document.location.href.split('#')[1];
            if(hash && hash.length > 0 ){
                windchillStore.setItem(URL_FRAGMENT_KEY , hash);
            }else{
                // clean-up, if left by previous incomplete login attempt.
                windchillStore.removeItem(URL_FRAGMENT_KEY);
            }
        }
    }
    function submit(){
        saveURLFragment();
        document.forms[0].submit();
    } 
</script>
<!-- PTC Recommended Customization(3) End  -->

 

 

 

 

If you modified any templates you can run a regenAllWebapps command from the httpserver folder again similar to when you turn on ProtocolAuthOnly (

ant -DprotocolAuthOnly=true -f webAppConfig.xml regenAllWebApps)

 

Another note, if you use Desktop Integration, you need to modify the following files accordingly:

The DTILogin action of the connect command must be defined as WIZARD, for this use the below steps:

  • Go on Windchill server and Edit files below :
    • \Windchill_12.0\Windchill\codebase\com\ptc\windchill\enterprise\nativeapp\msoi\client\xml\wtOffice.xml
    • \Windchill_12.0\Windchill\codebase\com\ptc\windchill\enterprise\nativeapp\msoi\client\xml\wtDesktop.xml
    • \Windchill_12.0\Windchill\codebase\com\ptc\windchill\enterprise\nativeapp\msoi\client\xml\wtWindows.xml
  • For each of them replace :
    • <action serverAction="DTILogin" type="HTTP"></action>
      • With
    •  <action serverAction="DTILogin" type="WIZARD"></action>
  • Restart Windchill
avillanueva
22-Sapphire II
(To:jbailey)

I will take another look here. PTC instruction was strange. I one place they said to copy their file they provided and other place they said strongly NOT to do that. I ended up cutting and pasting sections in. Thanks again for all your help.

avillanueva
22-Sapphire II
(To:jbailey)

I think there is some poor documentation. Help Docs do show sample changes for the bindingTemplate.html with 3 customization sections. The same file they reference, one, is not in that location but did find it, and two, only has two customization sections. I see what is missing and an added that back in.

Lot's of poor documentation / conflicting instructions. I helped troubleshoot this before it was officially supported (In WC 11.2) where the components were there, but not officially supported. I sent a bunch of comments back and suggestions for updates to documentation. Several things were never updated

avillanueva
22-Sapphire II
(To:avillanueva)

I justed wanted to return to this thread and close it out thought I still have a few more loose ends to wrap up. Thank you so much to @jbailey for all your help. We actually took this offline to keep thread smaller. Here is a summary of what I learned:

  • Metadata file must reference your proxy so that should be the domain you present to IDP.
  • bindingTemplate.html CAN be copied from PTC codebase so long as you are not doing anything fancy. Documentation has wrong location. Its in the codebase/templates folder not WEB-INF. 
  • PTC HttpServer ServerName needed to match the proxy domain. This is what seemed to influence what shibboleth used in generating the Metadata file. I also received 404 errors getting the Metadata file when it did not match.
  • I still have issues with the sessionHook.jsp for which I have a PTC ticket on. Take note of this debug logger (sso.shibboleth.sessionHook). This was key to it complaining about the different domains. I was able to code around the issue but intend to return to OOTB hook. For now, its working as it should. I will try and collect my notes and write up something clearer.

Also all attribute-map does is takes an attribute with a name from the IdP (left side) and translate it to an attribute that Shibboleth will use, and REMOTE_USER mapped to that shibboleth attribute name to present to apache. It honestly doesn't matter what you use, as long as shibboleth knows the attribute it is getting and translates it to something your app will use. 

Top Tags