Fix (APAR): WAS_Security_02-24-2003_5.0.0_cumulative_Fix Release: 5.0.0 Operating System: All Supersedes Fixes: none Byte size of APAR: WAS_Security_02-24-2003_5.0.0_Client_cumulative_Fix.jar = 97256 WAS_Security_02-24-2003_5.0.0_cumulative_Fix.jar = 156296 Date: 2003-02-26 Abstract: Security cumulative Interim fix Description/symptom of problem: See APARs below: PQ71279, PQ71399 and PQ70395. Directions to apply fix: NOTE: YOU MUST FIRST DOWNLOAD THE UPDATEINSTALLER TOOL IN ORDER TO INSTALL A FIX. The UpdateInstaller can be downloaded from the following link: http://www-3.ibm.com/software/webservers/appserv/support/ 1) Create temporary "fix" directory to store the jar file: UNIX: /tmp/WebSphere/fix Windows: c:\temp\WebSphere\fix 2) Copy jar file to the directory 3) Shutdown WebSphere 4) Follow the installation instructions that are packaged with the UpdateInstaller on how to install the Fix. 5) Restart WebSphere 6) The temp directory may be removed but the jar file should be saved. Do not remove any files created and stored in the /WebSphere/AppServer/fix/ directories. These files are required if a fix is to be removed. Directions to remove fix: NOTE: FIXES MUST BE REMOVED IN THE ORDER THEY WERE APPLIED. DO NOT REMOVE A FIX UNLESS ALL FIXES APPLIED AFTER IT HAVE FIRST BEEN REMOVED. YOU MAY REAPPLY ANY REMOVED FIX. Example: If your system has fix1, fix2, and fix3 applied in that order and fix2 is to be removed, fix3 must be removed first, fix2 removed, and fix3 re-applied. 1) Shutdown WebSphere 2) Follow the instructions that are packaged with the UpdateInstaller on how to uninstall the Fix. 3) Restart WebSphere Directions to re-apply fix: 1) Shutdown WebSphere 2) Follow the instructions that are packaged with the UpdateInstaller on how to uninstall and reinstall the Fix. 3) Restart WebSphere Additional Information: PQ70395 WAS 5.0 JAAS WSLoginModule not use token authentication data. ERROR DESCRIPTION: When login with a valid token (LTPA in 5.0), the token validation fails with the following message: [11/25/02 15:47:35:625 CST] 4fe2b3fa WSLoginHelper E SECJ4008E: Missing some of the authentication data [11/25/02 15:47:35:816 CST] 4fe2b3fa WSLoginHelper E SECJ4001E: Login failed for secnt6.austin.ibm.com:389/ org.omg.SecurityLevel2.LoginFailed Environnment: WebSphere Application Server 5.0 AE LTPA authentication Mechanism Description: Customer has a simple servlet that is mapped to any URL starting with "/servlet/" . URLs starting with "/servlet/protected/*" are protected and the login method is set to Basic. The security is enabled and authentication mechanism is set to use LTPA with user registry being LDAP. The servlet performs a login on every request. The user id and password are hardcoded in the code (for simplicity). However, if the request is for "/servlet/protected/*" , then it looks for an LTPA cookie. If that is found on the request, another login is performed, in order to get the dn of the user. This last step is where I hit some problems. Here is the source of the servlet and of a helper class, that does the login. (See wasdoc0:\\PMR\00026663649\export_1125a.jar (See wasdoc0:\\PMR\00026663649\SecurityTestApplication.ear) (See wasdoc0:\\PMR\00026663649\traceForRequestWithLTPAToke.log) ... Customerstated that the classes caused the problem are: WSLoginModuleImpl and WSCallbackHandlerImpl Test procedures: - Install SecurityTestApplication.ear. - From a browser enter request is http:/sta/servlet/aaa , the servlet will do a login with the hardcoded credentials. - From a vrowser enter request for /sta/servlet/protected/aaa; this is a protected URL and WAS will enforce basic authentication, when sucessful, the servlet will again do a login with hardcoded credentials. - From a browser enter /sta/servlet/secure/aaa ; the servlet will again do a login with hardcoded credentials but also, in this case, the servlet will look for LTPA cookie, which should have been generated by the previous request. When LTPA is found, another login will be attempted with this LTPA token. And this is the failing part. LOCAL FIX: PROBLEM SUMMARY: **************************************************************** * USERS AFFECTED: All WebSphere Application Server users * * creating JAAS login modules and using the * * LTPA authentication mechanism. * **************************************************************** * PROBLEM DESCRIPTION: WSLoginModuleImpl.login() fails when * * using LTPA. * **************************************************************** * RECOMMENDATION: * **************************************************************** WSLoginModuleImpl.login() fails when using LTPA. The error messages received are similar to the following: [11/25/02 15:47:35:625 CST] 4fe2b3fa WSLoginHelper E SECJ4008E: Missing some of the authentication data [11/25/02 15:47:35:816 CST] 4fe2b3fa WSLoginHelper E SECJ4001E: Login failed for someserver.some.domain.com:389/ org.omg.SecurityLevel2.LoginFailed The failure was due to the logic failing to use the LTPA token to validate the login. Instead, an attempt to use the user ID and password was done. However, the user ID and password was no longer available. PROBLEM CONCLUSION: This is resolved in internal defect 154797. The LTPA token is now used for validating the login. TEMPORARY FIX: WAS_Security_02-24-2003_5.0.0_cumulative_fix.jar COMMENTS: PQ71279 Client cannot retrieve detailed error messages from WSAS5.0 CustomRegistry ERROR DESCRIPTION: Environment: Win2K, WSAS 5.0 Base WebSphere Security Custom Registry issue. The customer has a customRegistry program on server side and they want to pass the detailed error messages from customRegistry to the client code with the loginhelper class. Method checkPassword from customRegistry class throws passwordCheckFailed exception with a message "password check exception userid = null". On the client, the request_login method of the loginHelper class throws a LoginFailed exception is WITHOUT including the above message. Customer considers this critical to their business and cannot wait till the ptf. So, they would like an efix on 5.0. Solution suggested by customer: ****************************** Reviewed the client trace MyTraceFile.log and found the following errors: org.omg.CORBA.NO_PERMISSION: Caught WSSecurityContextException in WSSecurityContext.acceptSecContext(), reason: Major Code 0 Minor Code 0 Message Cannot get credential because of the following error: password check exception userid = null minor code: 49424300 completed: No at com.ibm.ISecurityLocalObjectBaseL13Impl.PrincipalAuthFailReason. map_auth_fail_to_minor_code(PrincipalAuthFailReason.java:83) at com.ibm.ISecurityLocalObjectBaseL13Impl.CSIServerRI.receive_requ est(CSIServerRI.java:1706) at com.ibm.rmi.pi.InterceptorManager.iterateReceiveRequest(Intercep torManager.java:729) at com.ibm.CORBA.iiop.ServerDelegate.dispatchInvokeHandler(ServerDe legate.java:571) The stack trace, while simplified here, goes along this path MyApplication -> LoginHelperImpl -> CommonSecurityServer -> SecurityContextImpl 1) LoginHelperImpl - the one thing I notice here in several places is that the code throws exceptions like throw new LoginFailed(); Perhaps some of those are ok, but if there is more information, like the message text of a previous exception, that could be added in. - in this method public synchronized Credentials request_login_controlled(String security_name, String realm_name, String password, byte credential_token[], CredentialsHolder creds_holder, OpaqueHolder auth_specific_data, boolean store_in_default_creds_list, int authentication_target, boolean set_invocation_creds) throws LoginFailed eventually, this calls CommonSecurityServer.authenticate() like this ... CommonSecurityServer cSecServer = _vault.getCommonSecurityServer(4); AuthenticationResult authResult = null; authResult = cSecServer.authenticate(r_name, basicAuthData, false); if(authResult.get_auth_fail_reason() != 100) { logMsg = "Credential is null, BasicAuth creds did not authenticate."; SecurityLogger.debugMessage(logMethod, logMsg); //mike String blah = authResult.get_auth_fail_message(); System.out.println ("blah4=" + blah); throw new LoginFailed(null, blah); //throw new LoginFailed(); //mike } The code within the //mike comments are there to fix this problem. The message text from the custom registry is caught by the SecurityServer class and placed INTO the AuthenticationResult. Points of interest? - the call for cSecServer.authenticate, in the current code, causes 4 authentications to occur 2) CommonSecurityServer The method for authentication that is eventually called is private AuthenticationResult authenticate(String realm, BasicAuthData authenticationData, String name, byte token[], String methodName) In this method, there is a call to initSecurityServer b) initSecurityServer() This method does some code like if(securityServer == null) try { Class wrapperclass = Class.forName("com.ibm.WebSphereSecurityImpl.SecurityServerImpl" ); java.lang.Object wrapperObj = wrapperclass.newInstance(); securityServer = (SecurityServer)wrapperObj; if(securityServer != null && SecurityLogger.debugTraceEnabled) { logMsg = "Security Server is initialized."; SecurityLogger.debugMessage(logMethod, logMsg); } } catch(Exception e) { FFDCFilter.processException(e, "com.ibm.ISecurityUtilityImpl.CommonSecurityServer.initSecurityS erver", "102", this); logMsg = "security.JSAS0199E"; SecurityLogger.logError(logMsg, new java.lang.Object[] { logMethod }); //mike mike = ((NoPermissionException)e).getRootCause().getMessage(); } Read point 3 about SecurityServerImpl. What happens is that constructor completes successfully, even though 2 authentications have failed. So, the wrapperObj is an actual instance, and not NULL. No exception is thrown from the constructor in SecurityServerImpl. So, in this code, the securityServer object is created, and the method returns as if it was successful (when it hasn t been). This method should either throw or return something other than null. 3. SecurityServerImpl The base constructor for this is public SecurityServerImpl() throws Exception { securityServer = null; getSecurityServer(); } which would be invoked with the newInstance() call above. b) getSecurityServer() This code has an initial try/catch block trying to get an initial context. This catch dumps some stuff out to the trace logs, but then carries on. It then does a lookup on SecurityServer, which will also authenticate and fail. The first catch should do a throw, rather than continuing on to the second attempt. In the current code, if the SecuritySeverImpl constructor calls getSecurityServer, which does 2 authentications. This method just returns normally, even though it has not successfully connected to the mid-tier. The class that attempts to make this one gets back an object, rather than a null or an exception. c) simple_authenticate public boolean simple_authenticate(BasicAuthData basicauthdata) throws AuthenticationFailedException, AuthenticationNotSupportedException This method will check if the securityserver is set up (checking for null). Since it didn t work in the constructor, the code calls getSecurityServer() again. This will cause two more authentication failures. In the code I'd sent, in each of those classes I added some code commented with //mike. In there, I throw an exception from getSecurityServer(). This contains the message text of the exception thrown from the customregistry on the server side. This will cause the SecurityServerImpl to not be constructed. In the CommonSecurityServer class, it will now catch this exception, and I placed the message text into a member variable (too lazy to change that method (initSecurityServer) to throw). In this case now, the securityServer variable is now NULL, where without the fix, it was NOT NULL. Then, basically, for the code that calls initSecurityServer, it checks for securityServer being null. If it is, it can take the message we stored above, and include it in the AuthenticationResult. Then, way back in LoginHelperImpl, when it gets the AuthenticationResult, it can get this message and throw a new LoginFailed with that message text in it. LOCAL FIX: None PROBLEM SUMMARY: **************************************************************** * USERS AFFECTED: All WebSphere Application Server users * * creating JAAS login modules and using the * * LTPA authentication mechanism. * **************************************************************** * PROBLEM DESCRIPTION: WSLoginModuleImpl.login() fails when * * using LTPA. * **************************************************************** * RECOMMENDATION: * **************************************************************** WSLoginModuleImpl.login() fails when using LTPA. The error messages received are similar to the following: [11/25/02 15:47:35:625 CST] 4fe2b3fa WSLoginHelper E SECJ4008E: Missing some of the authentication data [11/25/02 15:47:35:816 CST] 4fe2b3fa WSLoginHelper E SECJ4001E: Login failed for someserver.some.domain.com:389/ org.omg.SecurityLevel2.LoginFailed The failure was due to the logic failing to use the LTPA token to validate the login. Instead, an attempt to use the user ID and password was done. However, the user ID and password was no longer available. PROBLEM CONCLUSION: This is resolved in internal defect 154797. The LTPA token is now used for validating the login. TEMPORARY FIX: WAS_Security_02-24-2003_5.0.0_cumulative_fix.jar COMMENTS: PQ71399 RETRY FLAG IN SECURITY.XML AND SAS PROPERTIES DOES NOT TAKE EFFECT. Problem: ------- The issue is related to authenticationRetryEnabled and authenticationRetryCount settings in security.xml file and sas.client.props file. Customer found that the client was authenticated twice from the server side when he provided the wrong password even if he disabled authenticationRetryEnabled flag. Environment: ----------- Win 2K WAS 5.0 Base Detailed description and workaround from customer: ------------------------------------------------- It 'seems' that when I do a bad userid and password, authentication happens MULTIPLE times, even though I have set the retry flags to 0 (in sas.client.props and the security.xml file on the server side). I first noticed this when I tried a bad password on my own account; we've a security rule set up in our RACF system that 3 bad password attempts will lock out your account. I locked it out once, and then looked thru the logs. I then turned off the retry flags, and still see multiple authentication attempts. And, the client side trace can be checked against the server side traces and you can see these multiple tries. I think the problem is in two classes: com.ibm.IsecurityUtilityImpl. CommonSecurityServer and com.ibm.WebSphereSecurityImpl.SecurityServerImpl Here's the problem: 1) In CommonSecurityServer, the last authenticate method will call initSecurityServer the first time. This ends up creating com.ibm.WebSphereSecurityImpl.SecurityServerImpl by Class.forName. The constructor for this class (thru a method called getSecurityServer) does an InitialContext, and then a lookup for "SecurityServer". Both of these cause authentications with the customregistry. So, here are two of the four authentication attempts. This constructor does NOT throw an exception, so the object seems to be constructed. Back in CommonSecurityServer, securityServer is NOT null. Here's a screen shot thru WSAD - the class is being created, where I would imagine that's not what is expected. 2) After this, since the securityServer is not null, the authenticate method continues on. The method simple_authenticate in SecurityServerImpl is called; it in turn calls getSecurityServer again, which causes the other 2 authentications. From there, I looked into the method getSecurityServer() in com.ibm.WebSphereSecurityImpl.SecurityServerImpl. This is where it does the initialcontext, and then a "securityserver" lookup, which causes the two exceptions. There are several catch blocks in this code - the catch blocks do some debug traces, but that's about it. In each of them, I threw the exception along, to let the call know about them. In this case, the caller class is com.ibm.IsecurityUtilityImpl.CommonSecurityServer and the method is initSecurityServer, which again is creating SecurityServerImpl with a class.forname(). Now, the exception will get back to this class, and the attempt to create the securityServer member will fail, and it will be null. In the authenticate method (which called initSecurityServer), it will see that securityServer is null, and create an AuthorizationResult and return. Possible Solution: ----------------- I've got this working now, at least for this problem. 1) Changes to com.ibm.IsecurityUtilityImpl.CommonSecurityServer - added String member variable named mike - in initSecurityServer(), in the catch block, set mike to ((NoPermissionException)e).getRootCause().getMessage(); - in authenticate, set the auth fail reason to mike, instead of logmsg. - I marked the code changes with the comment //mike 2) Changes to com.ibm.WebSphereSecurityImpl.SecurityServerImpl - again, commented additions with //mike - in getSecurityServer(), on the various catches, throw the exception so that CommonSecurityServer can deal with it, rather than doing nothing with it 3) changes to com.ibm.ISecurityLocalObjectBaseL13Impl.LoginHelperImpl - when creating a LoginFailed exception to throw to the client application, create it as new LoginFailed (null, authResult.get_auth_fail_message()); - I only changed some specific code for what I'm seeing in request_login_controlled - the final method. - Again, commented as //mike So, with these changes, I still see that I'm authenticating twice on the server side, but I haven't jarred up the above changes and stopped and restarted websphere. LOCAL FIX: None. PROBLEM SUMMARY: **************************************************************** * USERS AFFECTED: All WebSphere Application Server users * * using Java clients with security enabled * * and disabling authentication retries. * **************************************************************** * PROBLEM DESCRIPTION: Authentication retry logic cannot be * * disabled. * **************************************************************** * RECOMMENDATION: * **************************************************************** Authentication retry logic cannot be disabled. In addition, any attempt at authentication after a failed attempt results in a NO_PERMISSION exception. PROBLEM CONCLUSION: This problem was resolved by adding additional retry logic in the CredentialManager. This was resolved in internal defect 155026. TEMPORARY FIX: WAS_Security_02-24-2003_5.0.0_cumulative_fix.jar CIRCUMVENTION: No circumvention is available. The circumvention listed in the submission text breaks the users license agreement and should not be attempted.