Monday, November 12, 2007

Desktop Integrated Signon

Several months ago I had the opportunity to configure a PeopleSoft system to "trust" users' desktop credentials. Some would call this single signon or even Desktop Integrated Signon. Implementing desktop integrated signon requires some configuration and a small amount of development. The process looks like this:

  1. Download the JCIFS NtlmHttpFilter,

  2. Modify the filter to pass the desktop user name to the app server as a request header (compile and deploy included, of course),

  3. Write some signon PeopleCode,

  4. Enable public access,

  5. Enable signon PeopleCode, and

  6. Configure your web server to use your new filter (see the JCIFS NtlmHttpFilter documentation for configuration details as details will differ depending on your environment).

After downloading the filter and filter source code, open the NtlmHttpServletRequest and implement the getHeader and getHeaderNames overrides with the following code.

    public String getHeader(String name) {

if(name.equals("XX_REMOTE_USER") {
return getRemoteUser();
} else {
HttpServletRequest req = (HttpServletRequest)this.getRequest();
return req.getHeader(name);
}

}
public Enumeration getHeaderNames() {
Vector headers = new Vector();
HttpServletRequest req = (HttpServletRequest)this.getRequest();

for (Enumeration e = req.getHeaderNames() ; e.hasMoreElements() ;) {
headers.add(e.nextElement());
}

headers.add("XX_REMOTE_USER");
return headers.elements();
}

Next, put the following PeopleCode in a FUNCLIB:

Function WWW_NTLM_AUTHENTICATE()
Local string &userName = %Request.GetHeader("XX_REMOTE_USER");
Local number &foundSlash = Find("/", &userName);

REM ** remove the NT/AD domain;
If(&foundSlash > 0) Then
&userName = Substring(&userName, &foundSlash + 1, Len(&userName));
Else
&foundSlash = Find("\", &username);
If(&foundSlash > 0) Then
&userName = Substring(&userName, &foundSlash + 1, Len(&userName));
Else
End-If;

If(Len(&userName) > 0) Then
SetAuthenticationResult(True, &userName);
Else
SetAuthenticationResult(False, &userName, "Web server authentication failure");
End-If;
End-Function;

Like I said, it has been a few months since I wrote this code, and, unfortunately, I'm typing it here from memory. Please correct any mistakes I've made. Refer to PeopleBooks for enabling signon PeopleCode and enabling public access. Both are documented in the Security Administration PeopleBook.

A couple of issues I've found with this approach:

  • If you are using Enterprise Portal and want to allow desktop integrated signon to both the portal and to the content provider apps, then you will need to further customize the filter to skip NTLM on your content provider web servers when the client is the portal server. Otherwise, the NtlmHttpFilter will not allow portal to access those web servers (this only affects homepage creation when you have pagelets that come from a content provider). If you only access your PeopleSoft systems through Enterprise Portal, then this is not an issue. Likewise, if you are configuring this solution on your PeopleSoft applications and you do not have Enterprise Portal, then this is not an issue.

  • In this scenario, your app server trusts the security information provided by the web server, bypassing the app server's standard authentication routine. This may pose a security threat if users can gain access to your app server. To mitigate this risk, you may want to either hide your app server behind a firewall or perform additional validation/authentication (digitally encrypt the user ID request header on the web server with a certificate and decrypt it on the app server, pass the NTLM authentication token on to the app server and validate it again, etc).

  • Since this solution requires your web server to trust your desktop, make sure your organization has a strong password policy forcing strong passwords. If you use a desktop integrated sign on solution, then any user that can gain access to a desktop by cracking a password can also gain access to your Enterprise applications. As an alternative to passwords, consider key fobs.

If you would like to allow administrators to log in as someone other than their desktop user (psadmin, for example), then you can add an "if" test to your signon PeopleCode that compares %SignonUserId to the public user name. If the user name is the same as your public user name, then log the user into the application as the user given by the web server. Otherwise, return from this function and allow the standard signon processing to authenticate the user.

67 comments:

Wizard of Hope said...

Thanks a lot for this post. it was quite helpful to understand the External Desktop based SSO. We are considering it as one of the option. Thanks

Jim Marion said...

@Wizard, I am pleased that you find this information helpful. PeopleSoft security is extremely flexible. With this flexibility comes responsibility. Whatever you do, just make sure it is secure as well as user friendly.

kalyan_g43 said...

Hi Jim, we tried to use JCIFS NTLM authentication but there is aparently an issue with IE 7. When user clicks the X button to close the application, next time the user can not use the SSO link without clearing the browser cache and offline files.

Jim Marion said...

@kalyan_g43, it is the cookies. Rather than use the NTLM credential, PeopleSoft will use the existing PS_TOKEN cookie. By manually clearing cookies, you are able to create a new session. Clicking logout clears the session cookie. Clicking the x doesn't. If a user clicks the x, the cookie still exists.

The code above gives the basics, but doesn't take care of the session cookie. The way around the problem you are experiencing is to check for an existing web session. If one does NOT exist, then hide the PS_TOKEN cookie. When I implemented this solution, I used AOP (AspectJ) to instrument the jCifs code at design time. I overrode the getCookies() method so that if session.getAttribute("USERID") returned false, then I returned a new Cookie[] array that was a copy of the original without PS_LOGINLIST, PS_TOKENEXPIRE, and PS_TOKEN. If you aren't familiar with AOP, you can download a copy of the jCIFS source and modify the jcifs.http.NtlmHttpServletRequest class directly.

Another thing I did was modify jcifs.http.NtlmHttpFilter so that it skipped the NTLM filter for specific IP addresses. I can't remember why, but I think it had to do with RENS.

C said...

Hi Jim, When I tried to click on the NtlmHttpFilter link in step number 1, it redirected me to a page which says, " IMPORTANT: All HTTP related code and corresponding documentation in JCIFS is not supported, no longer maintained and will be removed because it is broken and obsolete (and because HTTP has nothing to do with CIFS). This page remains only for informational purposes and for legacy users. ". Does this mean that all the information in that page no longer applicable?

C said...

Hi Jim,
Thanks for your post. I'm planning to implement this to PeopleSoft HCM9. Is there any particular version of JCIFS that I will use? Where will I extract these files?
Thanks a lot for your help.

C said...

Hi Jim,
Sorry for throwing you a lot of questions. I'm not familiar with java language, i only know peoplesoft (sqr,peoplecode,sql,etc.) but not java, Just with regards to step 2, "Modify the filter to pass the desktop user name to the app server as a request header (compile and deploy included, of course),", can you please elaborate this further to a person who has a limited knowledge on java like me? :)

Jim Marion said...

@C, thank you for pointing out the deprecation of jCIFS. I had not noticed that. I will have to look into Jespa, the solution recommended by jCIFS.

About sending the user name to the app server, the code is in the post. I strongly suggest you learn some Java and learn something about Java web servers and servlet containers before trying to implement this solution. PeopleSoft uses a servlet container and supports Java, so your investment in this technology applies to PeopleSoft development.

C said...
This comment has been removed by the author.
C said...

Hi Jim,
Thanks for replying to my comments. After reading your comment, i had a crash course on Java. I modified NtlmHttpServletRequest.java and added the piece of code in your post and tried to recompile it but i'm encountering a lot of errors. I guess I'm recompiling it incorrectly. What I did is: Copied the modified NtlmHttpServletRequest.java to C:\Program Files\Java\jdk1.6.0_16\bin and executed javac NtlmHttpServletRequest.java from command prompt. What I'm planning after creating the NtlmHttpServletRequest.class is re-add it to jcifs.jar and replace the existing NtlmHttpServletRequest.class. Is this the correct way of recompiling a java?

C said...

Hi Jim,
Continuation from my previous comment, here the code for the new NtlmHttpServletRequest.java


package jcifs.http;

import java.security.Principal;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;

class NtlmHttpServletRequest extends HttpServletRequestWrapper {

Principal principal;

NtlmHttpServletRequest( HttpServletRequest req, Principal principal ) {
super( req );
this.principal = principal;
}
public String getRemoteUser() {
return principal.getName();
}
public Principal getUserPrincipal() {
return principal;
}
public String getAuthType() {
return "NTLM";
}
public String getHeader(String name) {
if ( name.equals ("XX_REMOTE_USER")) {
return getRemoteUser();
} else {
HttpServletRequest req = (HttpServletRequest)this.getRequest();
return req.getHeader(name);
}
}
public Enumeration getHeaderNames() { Vector headers = new Vector();
HttpServletRequest req = (HttpServletRequest)this.getRequest();
for (Enumeration e = req.getHeaderNames() ; e.hasMoreElements() ;) {
headers.add(e.nextElement());
}
headers.add("XX_REMOTE_USER");
return headers.elements();
}
}

C said...

and here's the error I got.

C:\Program Files\Java\jdk1.6.0_16\bin>javac NtlmHttpServletRequest.java
NtlmHttpServletRequest.java:23: package javax.servlet.http does not exist
import javax.servlet.http.HttpServletRequest;
^
NtlmHttpServletRequest.java:24: package javax.servlet.http does not exist
import javax.servlet.http.HttpServletRequestWrapper;
^
NtlmHttpServletRequest.java:26: cannot find symbol
symbol: class HttpServletRequestWrapper
class NtlmHttpServletRequest extends HttpServletRequestWrapper {
^
NtlmHttpServletRequest.java:30: cannot find symbol
symbol : class HttpServletRequest
location: class jcifs.http.NtlmHttpServletRequest
NtlmHttpServletRequest( HttpServletRequest req, Principal principal ) {
^
NtlmHttpServletRequest.java:51: cannot find symbol
symbol : class Enumeration
location: class jcifs.http.NtlmHttpServletRequest
public Enumeration getHeaderNames() { Vector headers = new Vector();
^
NtlmHttpServletRequest.java:47: cannot find symbol
symbol : class HttpServletRequest
location: class jcifs.http.NtlmHttpServletRequest
HttpServletRequest req = (HttpServletRequest)this.getRequest();
^
NtlmHttpServletRequest.java:47: cannot find symbol
symbol : class HttpServletRequest
location: class jcifs.http.NtlmHttpServletRequest
HttpServletRequest req = (HttpServletRequest)this.getRequest();
^
NtlmHttpServletRequest.java:47: cannot find symbol
symbol : method getRequest()
location: class jcifs.http.NtlmHttpServletRequest
HttpServletRequest req = (HttpServletRequest)this.getRequest();
^
NtlmHttpServletRequest.java:51: cannot find symbol
symbol : class Vector
location: class jcifs.http.NtlmHttpServletRequest
public Enumeration getHeaderNames() { Vector headers = new Vector();
^
NtlmHttpServletRequest.java:51: cannot find symbol
symbol : class Vector
location: class jcifs.http.NtlmHttpServletRequest
public Enumeration getHeaderNames() { Vector headers = new Vector();
^
NtlmHttpServletRequest.java:52: cannot find symbol
symbol : class HttpServletRequest
location: class jcifs.http.NtlmHttpServletRequest
HttpServletRequest req = (HttpServletRequest)this.getRequest();
^
NtlmHttpServletRequest.java:52: cannot find symbol
symbol : class HttpServletRequest
location: class jcifs.http.NtlmHttpServletRequest
HttpServletRequest req = (HttpServletRequest)this.getRequest();
^
NtlmHttpServletRequest.java:52: cannot find symbol
symbol : method getRequest()
location: class jcifs.http.NtlmHttpServletRequest
HttpServletRequest req = (HttpServletRequest)this.getRequest();
^
NtlmHttpServletRequest.java:53: cannot find symbol
symbol : class Enumeration
location: class jcifs.http.NtlmHttpServletRequest
for (Enumeration e = req.getHeaderNames() ; e.hasMoreElements() ;) {
^
14 errors


Any thoughts? I'm sure I'm doing this incorrectly. Any advise will greatly appreciated.

Thanks,

Jim Marion said...

@C, I have some thoughts. I recommend downloading an IDE like JDeveloper, NetBeans, or Eclipse. In your IDE, import all of the source from jcifs. Then you can modify the *.java file in place. When you are ready to deploy, use your IDE's features to package as a jar file or deploy all the files directly as *.class files.

Another note: When you compile, you need to set a compiler flag for your WebLogic/WebSphere's Java version.

Java files must exist in a folder hierarchy that matches the class's package. That is why you see so many errors when trying to compile the file in the bin directory. You can compile Java from the command line, but if you are new to Java, I recommend an IDE. The IDE will handle the compiler options and package structure for you.

Since you are compiling a ServletFilter, you need to add a J2EE jar file to your class path. Again, an IDE will manage this for you.

C said...

Hi Jim,
I really appreciate helping me on this! I hope you don't mine bombarding you more questions.

Looking on the step to modify the web.xml file, how come the user and password is included/hardcoded in the code? How will I modify this so that I automatically get the username and password that is currently login to the desktop?
Thanks

C said...

Hi Jim,
Looking into the link "NtlmHttpFilter", do I need to complete all the steps below? Is it enough to just modify and compile the NtlmHttpServletRequest and the web.xml?

Installation and Setup
Non MSIE Clients and "Basic" Authentication
JCIFS Properties Meaningful to NTLM HTTP Authentication
Must Restart The Container
Tomcat
MalformedURLException: unknown protocol: smb
Transparent Authentication and the Network Password Dialog
Personal Workstation AD Security Policy
HTTP POST and Protecting Sub-Content
SMB Signatures and Windows 2003
NTLM HTTP Authentication Protocol Details

Jim Marion said...

@C, yes, compiling and changing web.xml is enough

About the username and password... that is the username and password used by jCIFS to connect to your directory server to verify the desktop user. jCIFS will receive the desktop credentials and will send those off to the directory server for validation. To validate the credentials, jCIFS needs to log into the directory server. It uses the web.xml credentials to authenticate the desktop credentials. Once verified, the desktop credentials are passed on to PeopleSoft.

C said...

Hi Jim,
Thanks again for your response. It's getting clearer now but I think I'm a little bit confused. So to summarize, Can you confirm if this are correct?

In Web.xml example:
1.) jcifs.smb.client.domain ("NYC-USERS" from the example) is actually the Domain which the user is connected to
2.) jcifs.smb.client.username ("somenycuser" from the example) is the username of the administrator to use to login to the directory Server, not the end-user logging into the windows.
3.) jcifs.smb.client.password ("AReallyLoooongRandomPassword" from the example) is the password of the administrator to use to login to the directory server.

Are these correct?
Thanks!

C said...

It's working now.
Thanks a lot Jim!

Jim Marion said...

@C, good work! Glad to hear it!

C said...

Hi Jim, It's me again. Just wanted to ask:
Once this is implemented, then users will no longer have the ability to change or use their PeopleSoft Password. Is this correct?

C said...

Continuation to the previous post...
Users can change the PeopleSoft Password, but It wouldn't matter anymore since PeopleSoft authentication is just based on the windows login, not on the peoplesoft password of the user.

Jim Marion said...

@C, correct. Users can change their passwords, but it will have no affect.

samy said...

Hi Jim,

You have mentioned that its possible to allow login through admin account even if desktop SSO is implemented.

I believe we change the cmd=login to cmd=start in signon.html and need to replace this in all the html files used in the web profile.
I am not able to figure out how to allow admin account login.
Kindly help as I have reached a deadend...

Regards,
Samy

Jim Marion said...

@samy, I am afraid I am not familiar with the differences between cmd=start and cmd=login. I can tell you, however, how to bypass the code above for administrative users. As I mention at the end of the post, surround your signon PeopleCode with

if (%SignonUserId = "WEB PROFILE PUBLIC USER ID") then
... code above goes here
end-if;

Once you have this code in place, navigate to http://yourserver/yoursite/signon.html

Walucas said...

Hi Jim!
It's my first time in your blog, and i am happy to see all the information here! I am sure I will use a lot of it!
I have a question, can we configure the peoplesoft to enable login via HTML POST or GET methods?
Thanks a lot!

Jim Marion said...

@Walucas, thank you for the compliment. Yes, you can log into PeopleSoft via HTTP POST. Just POST to http(s)://yourserver:port/psp/site?cmd=login. In fact, if you want to take a user directly to a specific page/transaction, just post values for "userid" and "pwd" to the target transaction URL.

Walucas said...

It works Jim! Thanks again!

TC said...

Hello Jim, we are implementing External Desktop SSO to our PeopleSoft Portal 9.0 for the first time and we appreciate all the information you have provided within your blog. The question we have is if we are using Weblogic 8.1 SP1 within our environment which web.xml should we use to modify to insert the filter? When we do a search we come up with multiple web.xml files. Can you assist us on which specfic web.xml we should be modifying within the webserv folder?

Jim Marion said...

@TC, if you look at the folder structure for your PeopleSoft web server, you should see a PORTAL (or PORTAL.war) folder. You want the web.xml in the PORTAL/WEB-INF directory. The PORTAL web application is the "default" web application and is the one used to serve the PeopleSoft online application. PSIGW, pspc, etc, are for other PeopleSoft applications, but not the online application.

TC said...

Jim,
Thanks so much for clarifying which web.xml to edit. You have been a tremendous help for us. I have another question, however. (and, I may have some more as I later on) Now, it's about FUNCLIB record... which FUNCLIB should I edit to add you sample code - FUNCLIB_PWDCNTL OR FUNCLIB_LDAP?

Jim Marion said...

@TC, I would create my own so you don't have to worry about upgrades and patches overwriting your work. Create a new derived/work record, add the FUNCLIB field to it, and then add a new function to the FieldFormula event of the FUNCLIB field.

TC said...

Jim,
More questions... sorry...
I have finally compiled the java source codes using the jdeveloper. You mentioned that you can deploy the class files and not generate the jar file. What folder in %ps_home%\..\webserv\ do I copy the class files? Again, thanks in advance.

Jim Marion said...

@TC, if you don't put them in a jar file, then deploy them to %PS_HOME%\webserv\...\PORTAL\WEB-INF\classes.

jarodmerle said...

Hi Jim,

Sorry to drag back up an old topic, but I have a semi-related issue I'm trying to find a solution for.

Do you think something like this could be utilized to authenticate a PS user (logged in to a Windows desktop) against an ASP .NET web service (asmx) that has Integrated Windows Authentication enabled? I am unfamiliar with exactly how IWA works, but it seems to authenticate using NTLMSSP (that or Kerberos).

We actually use Grey Sparling's desktop single sign on product to authenticate users into PeopleSoft
I just don't know how one goes about "passing" the user's credentials, through the app and web servers, to the web service itself when making the call from a PeopleSoft application.

Thanks,
Jarod

Jim Marion said...

@Jarod, as I understand, you already have your PeopleSoft app authenticating against your directory server and using your desktop credentials. For ASP.NET, you will likely be using IIS for your web server. IIS already has a checkbox for turning on desktop integrated signon. All you have to do to your .NET app is tell it to get the user name from the Request object.

jarodmerle said...

@Jim

Maybe this is another ignorant question, but by that do you mean that the logged in username (on the windows side) should be sent in the HTTP request header when the web service is called? If so, how would I know the windows username of the person logged in to pass? It seems that %SignonUserId is only available in Sign On PeopleCode.

Jim Marion said...

@Jarod, I think I misunderstood your question. I thought you had a .NET web app that users were accessing from there desktop. I don't know why I thought that.

In PeopleCode, you can get the PeopleSoft user name using %OperatorId. If you are using desktop integrated signon, then chances are, %OperatorId is the same as your windows desktop user ID. The next question is, how do you send the Kerberos or NTLM token from PeopleSoft to your .NET application. I don't think you can - at least not without a bit of work. The desktop integrated sign on happens between the web server and the desktop. The web service call from your PeopleSoft app to the .Net app happens at your app server. To make this work, I think you need to store the SSO token from your signon PeopleCode and then access that token when you make the web service call. The web server sends the SSO token to signon PeopleCode on the initial request as one of the request headers.

jarodmerle said...

@Jim

Yes, we are hitting the ASMX web service from PeopleSoft in our situation.

In our case, %OperatorID isn't the same as the windows user ID unfortunately. I do have other means of deriving it from that, it's just not as clean as using a system variable or something.

Like you said though, my big problem is how to pass the credentials when the web service gets called. I will definitely look into your ID of grabbing the SSO token and passing it in the HTTP header when the web service is called. It may end up being easier said than done, but it's much more of an idea than I had about it (which was nothing at all :)).

Thank you very much.

SKBodiga said...

Hello Jim
I have followed steps mentioned in the post, but could not succeed. I might be missing something on configuration. I getting following error when try to access http://yourserver/yoursite/signon.html .




Error 404--Not Found
From RFC 2068 Hypertext Transfer Protocol -- HTTP/1.1:
10.4.5 404 Not Found
The server has not found anything matching the Request-URI. No indication is given of whether the condition is temporary or permanent.

If the server does not wish to make this information available to the client, the status code 403 (Forbidden) can be used instead. The 410 (Gone) status code SHOULD be used if the server knows, through some internally configurable mechanism, that an old resource is permanently unavailable and has no forwarding address.

could you please let me know how to trace the cause for this issue?

Jim Marion said...

@SKBodiga, I'm not sure what would cause the 404 errors. This means the web server was not able to find a mapping for the URL. I suggest you look at your web server logs. If you remove the NtlmHttpFilter servlet mapping, do you still get the 404?

SKBodiga said...

Hello Jim
Thanks, that was quick response. Yeah it was the issue with "Class file not found" I could resolve it by entering the jar file location in setenv.bat of webserver.

Now it is working fine. I have one more query in fact a requirement. In my scenario I want some users to login using peoplesoft authentication as they are not a part of ACtive Directory,How can I do this?

Do I need to make any changes to this setup?

Thanks in advance

-SKBodiga

Jim Marion said...

@SKBodiga, I had to do that as well. On the signon PeopleCode side, I added tests for particular user ID's. In my case, it was just the administrator. I believe I also had to make some change to the ServletFilter to get it to bypass NTLM authentication for particular users/ip addresses, but I can't remember.

SKBodiga said...

Hello Jim

I was able to do it by creating two different sites one for desktop SSO users and another for user who require peoplesoft authentication and added two filter mapping in web.xml and redirected to corresponding servelet.

It worked for me. I need to further test.

Thanks Jim for all your help.

Jim Marion said...

@SKBodiga, that makes sense. Did you need to add a test case to your Signon PeopleCode to bypass the token verification for the second site?

SKBodiga said...

No Jim, I didn't add anything in signon peoplecode all I had to do was to use different "?cmd" in the link. for peoplesoft authentication it is "?cmd=login" and for Desktop SSO "?cmd=start".

As I used filter-mapping to use peoplesoft servlet class for athentication, that bypasses the NTLM servlet and for the signon peoplecode even it gets executed will be of no use when it doesnot find the username(ADid).
that way it worked.



One morething I forgot to mention,I used different webprofiles for each site.

SKBodiga said...

We need to add one condition in Signon Peoplecode to get authenticated by Peoplesoft otherwise you will get "Web server authentication failure"

The changed code as follows

If (&foundSlash > 0) Then /* Added to avoid error */
If (Len(&userName) > 0) Then
SetAuthenticationResult( True, &userName);
Else
SetAuthenticationResult( False, &userName, "Web server authentication failure");
End-If; /* Added to avoid error */
End-If

Vikas Bhartiya said...

Hi Jim,
dont know if this is the right post to put this question on:
I have a page which saves data as soon as the user clicks on a view_details button. this means, if there are two users working on the same rows of the base records, one or the other will get a "Page data inconsistent with the database" error. On page activate, I want to be able to query whether another user is working on the same rows on the same page and show a message if this is true. Have you ever done this?

Thanks for your help as always..
Vikas

Jim Marion said...

@Vikas, The OTN Forum would be a better place to ask this.

I was just reading about PeopleSoft's optimistic locking design in David Kurtz's PeopleSoft for the Oracle DBA book.

You can do what you desire. If the record has a last modified date/time stamp, it will be really easy because you can SQLExec that field and compare to the current time, or, actually if the DB is different, then Just return a true/false by comparing the last update time stamp to the database current time stamp. If you don't have a last update time stamp, then you will have to perform a field by field, row by row compare. Not fun.

Kannan Chidambaram said...

Jim,

We are trying to Desktop Integrated Signon to PeopleSoft. You are having very useful information People Like me. I am going to learn Java basics as per advice and going to implement this. Your also all posts on 2007 but there so much changes in JCIFS between. Do you want to me download latest on or JCIFS delivered before 2007. Please advice me

Jim Marion said...

@Kannan,

You are right, a lot has changed. This post was for NTLM. Most today should use Kerberos. I haven't kept up with jcifs because PeopleTools now includes the Kerberos SDK. If you are using 8.51 or higher, take a look at the PeopleTools Kerberos SSO SDK. It implements a lot of the same principles as outlined here, but uses kerberos instead of NTLM.

Kannan Chidambaram said...

Jim,

Thanks for your response. We are using PeopleTool 8.48.09, HCM 9 and Weblogic 8.1. I have downloaded JCIFS(1.3.17) htlmhttp filter and Jdeveloper. I did edit the NtlmHttpServletRequest.java and set version to 1.4 from default. I got the following warning. Can you please advice me?

Jim Marion said...

@Kannan, your error didn't post.

Kannan Chidambaram said...

Hi Jim,

I got the following warning message when i compile in Jdeveloper form NTMLHTTPURLCONNECTION.JAVA

Warning(539,38): decode(java.lang.String) in java.net.URLDecoder has been deprecated

I am expecting your guidance to correct this warning message.

Jim Marion said...

@Kannan, you can usually ignore warnings. The decode(String) method still exists, but Java recommends that you use the decode(String, String) method instead. The deprecated method does not specify a character encoding. If you want to resolve it, replace it with decode(thevariable, "UTF-8"). See this example on Stack Overflow.

Kannan Chidambaram said...

Jim,


I am very sorry to keep disturbing you and hope you don't mind to clarify doubts. I have two issues.

1. I got the following error when i compile the java

Project: C:\Users\kchidamb\Desktop\Single Sign on\Java Code\jcifs-1.3.17\jcifs-1.3.17.jpr
C:\Users\kchidamb\Desktop\Single Sign on\jcifs-1.3.17\jcifs_1.3.17\src\jcifs\http\NtlmHttpServletRequest.java
Error(51,42): ')' expected
Error(60,10): cannot find class Vector
Error(60,31): cannot find class Vector

2. How to move this code to Weblogic server.

I appreciate your timely help

Thanks,
Kannan

Jim Marion said...

@Kannan, you may have to change the Java to make it work. This post was for Java 1.4 and is 5 years old. You can still use it, but will need to update some of the code to user newer versions of Java.

To deploy, copy the class files into your webserver's PORTAL/WEB-INF/class es or WEB-INF/lib directory.

Kannan Chidambaram said...

I was able to fix the java code issue, compiled java files and moved class files as you as said. I also added Peoplecode and enabled single signon.

I got the following error in Weblogic log.


#### <> <> <[ServletContext(id=78388235,name=PORTAL,context-path=)] Servlet failed with IOException
java.lang.Throwable: LDAP.MYDOMAIN.COM
at jcifs.netbios.NameServiceClient.getAllByName(Ljcifs/netbios/Name;Ljava/net/InetAddress;)[Ljcifs/netbios/NbtAddress;(NameServiceClient.java:307)
at jcifs.netbios.NbtAddress.getAllByName(Ljava/lang/String;ILjava/lang/String;Ljava/net/InetAddress;)[Ljcifs/netbios/NbtAddress;(NbtAddress.java:463)
at jcifs.smb.SmbSession.getChallengeForDomain()Ljcifs/smb/NtlmChallenge;(SmbSession.java:75)
at jcifs.http.NtlmHttpFilter.negotiate(Ljavax/servlet/http/HttpServletRequest;Ljavax/servlet/http/HttpServletResponse;Z)Ljcifs/smb/NtlmPasswordAuthentication;(NtlmHttpFilter.java:157)
at jcifs.http.NtlmHttpFilter.doFilter(Ljavax/servlet/ServletRequest;Ljavax/servlet/ServletResponse;Ljavax/servlet/FilterChain;)V(NtlmHttpFilter.java:121)
at weblogic.servlet.internal.FilterChainImpl.doFilter(Ljavax/servlet/ServletRequest;Ljavax/servlet/ServletResponse;)V(FilterChainImpl.java:27)
at weblogic.servlet.internal.WebAppServletContext$ServletInvocationAction.run()Ljava/lang/Object;(WebAppServletContext.java:6987)
at weblogic.security.acl.internal.AuthenticatedSubject.doAs(Lweblogic/security/subject/AbstractSubject;Ljava/security/PrivilegedAction;)Ljava/lang/Object;(AuthenticatedSubject.java:321)
at weblogic.security.service.SecurityManager.runAs(Lweblogic/security/acl/internal/AuthenticatedSubject;Lweblogic/security/acl/internal/AuthenticatedSubject;Ljava/security/PrivilegedAction;)Ljava/lang/Object;(SecurityManager.java:121)
at weblogic.servlet.internal.WebAppServletContext.invokeServlet(Lweblogic/servlet/internal/ServletRequestImpl;Lweblogic/servlet/internal/ServletResponseImpl;)V(WebAppServletContext.java:3892)
at weblogic.servlet.internal.ServletRequestImpl.execute(Lweblogic/kernel/ExecuteThread;)V(ServletRequestImpl.java:2766)
at weblogic.kernel.ExecuteThread.execute(Lweblogic/kernel/ExecuteRequest;)V(ExecuteThread.java:224)
at weblogic.kernel.ExecuteThread.run()V(ExecuteThread.java:183)
at java.lang.Thread.startThreadFromVM(Ljava/lang/Thread;)V(Unknown Source)
>

Please let me your thought

Jim Marion said...

@Kannan, good job resolving all of the other issues! Is your Microsoft domain server named LDAP.MYDOMAIN.COM? It sounds like the jcifs servlet is not able to connect to LDAP.MYDOMAIN.COM.

Gustavo Polkman said...

Hi Jim, I have an issue in my environment. In the past, we implemented your solution on a PT8.45 env and it's working fine. But after upgrading to PT8.52, it's not working anymore. We tried and the sentence "%Request.GetHeader("XX_REMOTE_USER");" it seems that it doesn't work, because the &userName variable it's empty.
We are using the same Jcifs than before (1.2.25b version) even we tried with the last one, but it didn't work too.
The new web.xml file was configured the same as the old one.
We have a WAS 7 webserver over a AIX machine, so we can't implement Desktop Single Sign On with Kerberos, according to the Oracle Support.
PIA_servlets logs shows the following:

WARNING psft.pt8.auth.PSCacheHashTable init PSCacheHashTable: warning, configDir doesn't exist: %WEBSERVER_HOME%/%DOMAIN_NODE%/%WEBAPP%/WEB-INF/psftdocs

System.out shows:
PSAuthenticator authenticate QEDMO Web server authentication failure

Application Server log shows:
PSAuthenticator authenticate QEDMO
Web server authentication failure
Failed to execute GetCertificate request

Do you have any ideas?
Regars
Gustavo

Jim Marion said...

@Gustavo, it is good to hear that you had everything working before. I don't see any reason it would stop working after an upgrade. The PIA_servlets.log file is specific to PeopleSoft servlets and won't likely log errors from the JCIFS ServletFilter. Take a look at your web server's stdout and stderr log files as well.

Gustavo Polkman said...

Hi Jim, I couldn't find any error on the files you mentioned. The only thing that I noticed when editing Java class (I'm not a Java programmer) for the latest JCIFS version is that in getHeaderNames function the Eclipse editor shows warnings like the following:

Type ArrayList is a raw type. References to generic type ArrayList should be parameterized

Or the following error in "headers.add(e.nextElement())":

The method add(string) in the type vector string is not applicable for the arguments (Objects)

So, do you have any idea what to check/review?
Regards,
Gustavo

Jim Marion said...

@Gustavo, I believe those are just warnings (yellow squiggly instead of red squiggly) telling you that Java 1.6 has a better way to handle Collections, but the old way still works.

Other than confirming everything is configured, I don't have any idea why it isn't working. You might try checking your HTTP requests from browser to server using Fiddler to make sure you are getting the NTLM challenge response. If you have Firefox and don't have it configured for NTLM, it will prompt you to allow NTLM, so that will be a good indicator that the ServletFilter is working as well. Another point to check is to see if your web server is validating tokens against your directory server. You can check this with a network sniffer configured to trap communication between your web server and directory server. I don't think you will be able to decipher the communication. The key is just whether it actually connected and received a response.

The other thing to check is to ensure that your signon PeopleCode is firing. But the fact that you are able to test the value of XX_REMOTE_USER tells me you already tested that. You might also print all of the HTTP headers to a file to see if the header has a different name.

In your servletfilter, you can also print to a file to make sure that it is handling requests. If you aren't seeing output in a log file for each request, then your servlet filter isn't getting called and that would point to a web.xml configuration issue.

Chandra Pal Rawat said...

Dear Jim,
I have a query that we are facing some session overridden issues in production.
Actually we are invoking peoplesoft SIGNON peoplecode with a diffent user.
At signon peoplecode there are two options either using %singonuser or you can set a particular user account. we have set a user to invoke the signon peoplecode.


But it seems like sometimes sessions are getting overidden as to invoke signon peoplecode the user is same for different users.

Could you please suggest how to avoid session overlapping.

Arshad said...

Hi Jim

Sorry to revive one of your old blog posts. I am trying to find some information on implementing SSO for PeopleSoft (PT 8.54) using ADFS (SAML2.0 or later) but cant seem to find any information on this.

Do you know if this is possible to do? If yes, does it require any additional components? I was reading in one of the forums that they used IIS as a proxy server for the integration between PeopleSoft and ADFS.

However I cannot find any detailed information on this. Let me know if you can help with this.

Regards
Arshad

Jim Marion said...

@Arshad, the only supported method for implementing SAML 2.0 is to use Oracle Identity Suite in front of PeopleSoft. There are several organizations, however, that are quite happy with their Shibboleth implementations.

Rajat said...

hello Jim,

We are upgrading Peoplesoft Tools from PT 8.51 to PT 8.54.14. We had Kerberos SSO with AD working fine with PT 8.51 but we are struggling to get it working with PT 8.54. We see some changes to web.xml but overall Kerberos classes and signon peoplecode remains same. Any suggestion from you will be great. We are trying to do same steps as we did in PT 8.51.

Thanks
Rajat

Yvonne Fang said...

Hello Jim & Rajat,

I can't find anymore info and help from Oracle Supprot, wonder if you can share the knowledge with me.

We tried to follow PeopleTools 8.52 PeopleBooks to setup Kerberos SSO, the keytab file does contain the valid HTTP://@DOMAIN.COM but when web server boots and we issue the URL:////?/tab=DEFAULT command, it shows with "Invalid Token". The web server is running under local admin account, but when I try to setup startPIA as window service using the AD account (after the SETSPN command), it won't recognize this account. Do you know the PeopleSoft server needs to be running using the AD account we setup in AD?

Thanks,
Yi