Hi Guys, This seems to be a bug in WSS4J.
In the plain text password case the validator[1] should simply load the password into the callback and let the callback handler take care of authentication. IIRC this was the behavior earlier with the use of WSPasswordCallback.USERNAME_TOKEN_UNKNOWN. This allows the service developer to store any derived/hashed form of the password and then use the callback handler to process incoming passwords. Thanks, Ruchith 1.) http://svn.apache.org/repos/asf/webservices/wss4j/tags/1_6_4/src/main/java/org/apache/ws/security/validate/UsernameTokenValidator.java On Mon, Jan 21, 2013 at 6:59 AM, Martin Gainty <mgai...@hotmail.com> wrote: > > > > ________________________________ > From: brianreinh...@lampreynetworks.com > To: java-dev@axis.apache.org > Subject: RE: Rampart STS Username service not returning password in callback > Date: Sun, 20 Jan 2013 08:10:04 -0500 > > Martin, > > > > I’m not sure I follow what you are saying. Are you suggesting there is a > means to accomplish the same thing (get actual sent password in the > callback) without changing the code AND is compliant with WS-Trust clients? > > MG>yes...take this example from > org.apache.ws.security.dom.handler.CallbackRefTest > MG> > > private CallbackHandler callbackHandler = new > UsernamePasswordCallbackHandler(); > > /** > * A test for WSHandler.getPassword(...) where the password is obtained > from a > * Callback Handler, which is obtained from the handler options using a > ref. > */ > @org.junit.Test > public void > testHandlerOptionRef() throws Exception { > final WSSConfig cfg = WSSConfig.getNewInstance(); > final RequestData reqData = new RequestData(); > reqData.setWssConfig(cfg); > reqData.setUsername("alice"); > reqData.setPwType(WSConstants.PW_DIGEST); // type of requested > Password from response can be PW_TEXT > reqData.setMsgContext(new java.util.TreeMap<String, String>()); > final java.util.List<Integer> actions = new > java.util.ArrayList<Integer>(); > > /* Here are the options for our actions > > public static final int NO_SECURITY = 0; > public static final int UT = 0x1; // perform UsernameToken > public static final int SIGN = 0x2; // Perform Signature > public static final int ENCR = 0x4; // Perform Encryption > > public static final int ST_UNSIGNED = 0x8; // perform SAMLToken unsigned > public static final int ST_SIGNED = 0x10; // perform SAMLToken signed > > public static final int TS = 0x20; // insert Timestamp > public static final int UT_SIGN = 0x40; // perform signature with UT > secret key > public static final int SC = 0x80; // this is a > SignatureConfirmation > > */ > > int action=Integer.valueOf(WSConstants.UT); > actions.add(action); > > /* > > where UsernameToken class contains both username AND password elements > > private Element elementUsername = null; > private Element elementPassword = null; > > */ > > /* what is the soap envelope we will use for our document public static > final String SAMPLE_SOAP_MSG = > "<?xml version=\"1.0\" encoding=\"UTF-8\"?>" > + "<SOAP-ENV:Envelope " > + "xmlns:SOAP-ENV=\"http://schemas.xmlsoap.org/soap/envelope/\" " > + "xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\" " > + "xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\">" > + "<SOAP-ENV:Body>" > + "<add > xmlns=\"http://ws.apache.org/counter/counter_port_type\">" > + "<value xmlns=\"\">15</value>" > + "</add>" > + "</SOAP-ENV:Body>" > + "</SOAP-ENV:Envelope>"; > > */ > > //construct a simple SoapEnvelope doc with counter_port_type set to 15 > Document doc = SOAPUtil.toSOAPPart(SOAPUtil.SAMPLE_SOAP_MSG); > CustomHandler handler = new CustomHandler(); > > //public static final String PW_CALLBACK_CLASS = "passwordCallbackClass"; > handler.setOption(WSHandlerConstants.PW_CALLBACK_REF, > callbackHandler); > > //Notice the handler has not set the password but expects password from > response created by callback > handler.send( > WSConstants.UT, > doc, > reqData, > actions, > true > ); > > String outputString = > XMLUtils.PrettyDocumentToString(doc); > if (LOG.isDebugEnabled()) { > LOG.debug(outputString); > } > assertTrue(outputString.indexOf("alice") != -1); > assertTrue(outputString.indexOf("securityPassword") != -1); > } > MG> > > > > In any case, I think it’s an oversight by WSS4J that they require that the > service must KNOW the password. In the code I see no way to avoid the issue. > In all cases when the user’s (my) callback routine is signaled, the callback > passed to the user always has the password set to null and the user’s > callback routine is expected to provide the actual password. The latter part > is okay as a means to validate the password is okay, but what WSS4J needs to > do then is to provide a second routine, getSentPassword() which is the value > of the sent password, clear or digested. > > MG> recalling the password type is set in the RequestData > MG> reqData.setPwType(WSConstants.PW_TEXT); > > MG> String getSentPassword(Document doc,RequestedData > reqData,CallbackHandler callbackHandler,int Action,WSHandler handler) > > { > if(reqData.getPwType().equals(WSConstants.PASSWORD_DIGEST) > > { > > List<WSSecurityEngineResult> results = > secEngine.processSecurityHeader(doc, null, callbackHandler, null); > > WSSecurityEngineResult actionResult = > WSSecurityUtil.fetchActionResult(results, WSConstants.UT); > UsernameToken receivedToken = > (UsernameToken) > actionResult.get(WSSecurityEngineResult.TAG_USERNAME_TOKEN); > return receivedToken.hashCode()); > > } > > if(reqData.getPwType().equals(WSConstants.PASSWORD_TEXT) > > { > > callbackHandler=getPasswordCallbackHandler(reqData); > > WSPasswordCallback password_callback=handler.getPasswordCB( > reqData.getUsername(), > action, > callbackHandler, > reqData); > return password_callback.getPassword(); > > } > > } > MG> > > > > This would allow the service to respond as it sees fit. In my case that > would be storing a password digest so my service (and a successful hacker) > would never be able to know the real passwords. > > > > I would do that except the callback created implements ‘Callback’ which is > not part of WSS4J. Changing that interface looks like it would have FAR > reaching consequences. > MG>i think we can use WSPasswordCallback password_callback = > handler.getPasswordCB from WSHandler > > > > Brian > MG>WDYT > > > > From: Martin Gainty [mailto:mgai...@hotmail.com] > Sent: Saturday, January 19, 2013 7:40 PM > To: java-dev@axis.apache.org > Subject: RE: Rampart STS Username service not returning password in callback > > > > > > > > ________________________________ > > From: brianreinh...@lampreynetworks.com > To: java-dev@axis.apache.org > Subject: RE: Rampart STS Username service not returning password in callback > Date: Sat, 19 Jan 2013 08:58:15 -0500 > > Hi Martin, > > > > I did something different. The problem is in WSS4J. In the > UsernameTokenValidation file I simply passed the password to the callback > constructor which was previously null. Now I have to change the approach a > little bit. In my handler I read the password, do my hash, and if it matches > my stored hash I do nothing since the password is already set. This will > cause WSS4J to accept the message. If it doesn’t match I set the password to > current password + “bad” just to make it different causing the message to be > rejected. > > > > I don’t like it but I really saw no other choice and don’t understand why > WSS4J didn’t give the choice. They could have added another variable > ‘rawPassword’ and a getter for it. This would allow the service to use the > raw password for whatever purpose it needs. The user would still set > ‘password’ as expected by WSS4J. > > MG>take a look at the org.apache.ws.security.dom.message.WSSecUsernameToken > getSecretKey > > MG>/** > * getSecretKey > * > * After the <code>prepare()</code> method was called use this method > * to compute a derived secret key. If "useDerivedKey" is set, then the > returned secret > * key is derived as per the UsernameToken 1.1 specification. Otherwise, > the generation > * of this secret key is according to the WS-Trust specifications. > * > * @return Return the derived secret key of this token or null if > <code>prepare()</code> > * was not called before. > */ > > MG>boolean useDerivedKey is set to false initially so the secretKey coming > back from WSS4J is a WS-Trust compliant secretKey > MG>setting plain text Password can be accomplished with > MG>setPasswordType(WSConstants#PASSWORD_TEXT) > MG>setPasswordsAreEncoded(false) > MG>the prepare method sets the password into the UsernameToken object (in > the prepare method) > > MG>ut.setPassword(password); > > > > It works and I can store passwords as hashes and be interoperable with the > WS-Trust standard. > > MG>you have a solution..and thats all that matters > MG>congrats on acquiring a WS-Trust solution!..i hope the journey was > pleasant and as informative for you as it was for me > > > > Brian > > MG>Martin > > > > From: Martin Gainty [mailto:mgai...@hotmail.com] > Sent: Friday, January 18, 2013 11:24 PM > To: java-dev@axis.apache.org > Subject: RE: Rampart STS Username service not returning password in callback > > > > Hi Brian > > assume your CallbackHandler looks something like like > > public class PWCBHandler implements > javax.security.auth.callback.CallbackHandler { > public void handle(javax.security.auth.callback.Callback[] callbacks) > throws IOException, > javax.security.auth.callback.UnsupportedCallbackException { > for (int i = 0; i < callbacks.length; i++) { > org.apache.ws.security.WSPasswordCallback pwcb = > (org.apache.ws.security.WSPasswordCallback)callbacks[i]; > > put the CallbackHandler into the Options class for the serviceClient to > pickup e.g. > > Options options = client.getOptions(); > options.put(WSHandlerConstants.PW_CALLBACK_REF, new > PasswordCallbackHandler()); > > serviceClient.setOptions(options); > try { > //Blocking invocation > serviceClient.sendReceive(getOMElement()); > fail("Service Should throw an error.."); > } catch (AxisFault axisFault) { > assertEquals("Testing negative scenarios with Apache > Rampart. Intentional Exception", axisFault.getMessage()); > } > > http://wso2.org/library/3733 > > HTH, > Martin > ______________________________________________ > Verzicht und Vertraulichkeitanmerkung/Note de déni et de confidentialité > > Diese Nachricht ist vertraulich. Sollten Sie nicht der vorgesehene > Empfaenger sein, so bitten wir hoeflich um eine Mitteilung. Jede unbefugte > Weiterleitung oder Fertigung einer Kopie ist unzulaessig. Diese Nachricht > dient lediglich dem Austausch von Informationen und entfaltet keine > rechtliche Bindungswirkung. Aufgrund der leichten Manipulierbarkeit von > E-Mails koennen wir keine Haftung fuer den Inhalt uebernehmen. > > Ce message est confidentiel et peut être privilégié. Si vous n'êtes pas le > destinataire prévu, nous te demandons avec bonté que pour satisfaire > informez l'expéditeur. N'importe quelle diffusion non autorisée ou la copie > de ceci est interdite. Ce message sert à l'information seulement et n'aura > pas n'importe quel effet légalement obligatoire. Étant donné que les email > peuvent facilement être sujets à la manipulation, nous ne pouvons accepter > aucune responsabilité pour le contenu fourni. > > > > > > ________________________________ > > From: brianreinh...@lampreynetworks.com > To: java-dev@axis.apache.org > Subject: RE: Rampart STS Username service not returning password in callback > Date: Fri, 18 Jan 2013 12:01:19 -0500 > > Martin, > > > > Can you tell me where the password callback in my service gets called from? > It’s the password callback configured by the following line in the STS > service.xml > > > > > <ramp:passwordCallbackClass>com.lni.exchange.wan.receive.binding.axis2.PasswordCallback</ramp:passwordCallbackClass> > > > > > > Brian > > > > From: Martin Gainty [mailto:mgai...@hotmail.com] > Sent: Wednesday, January 16, 2013 5:14 PM > To: java-dev@axis.apache.org > Subject: RE: Rampart STS Username service not returning password in callback > > > > http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd > > i think I found an element we can use > > (where both noonce and Password would be child elements of > wsc:DerivedKeyToken) so here is the TestCase > > org.apache.rampart.handler.config.OutflowConfiguration ofc = new > org.apache.rampart.handler.config.OutflowConfiguration(); > > ofc.setActionItems("UsernameToken Encrypt"); > ofc.setUser("Mohammed"); > ofc.setAddUTElements("Nonce Created"); //Noonce > ofc.setEncryptionParts("{Element}{" + WSSE_NS + "}UsernameToken"); > ofc.setEncryptionUser("osama"); > ofc.setEncryptionPropFile("interop.properties"); > ofc.setPasswordCallbackClass("org.apache.axis2.security.PWCallback"); > ofc.setEncryptionSymAlgorithm(WSConstants.TRIPLE_DES); //change this to > MD5 or SHA-1 > ofc.setPasswordType(WSConstants.PW_TEXT); > ofc.setEncryptionKeyIdentifier(WSSHandlerConstants.SKI_KEY_IDENTIFIER); > > //so here is the new OutFlowConfiguration Element > ofc.setPassword("YadaYadaYada"); > > return ofc; > > //org.apache.rampart.handler.config.OutflowConfiguration change > public void setPassword(String passwordType) { > this.actionList[this.currentAction].put( > WSHandlerConstants.PASSWORD, password); > } > //org.apache.ws.security.dom.handler.WSHandlerConstants add this element > public static final String PASSWORD = "password" > > //correct ...why touch WSS4J for one minor update to a constant ..(maybe > using constant "password" is better) > > //org.apache.rampart.handler.config.OutflowConfiguration change with > constant > public void setPassword(String passwordType) { > this.actionList[this.currentAction].put( > "password", password); > } > > reference > http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd > > WDYT? > Martin >></xsd: > > ________________________________ > > No virus found in this message. > Checked by AVG - www.avg.com > Version: 2013.0.2890 / Virus Database: 2638/6037 - Release Date: 01/16/13 > > No virus found in this message. > Checked by AVG - www.avg.com > Version: 2013.0.2890 / Virus Database: 2638/6037 - Release Date: 01/16/13 > > ________________________________ > > No virus found in this message. > Checked by AVG - www.avg.com > Version: 2013.0.2890 / Virus Database: 2639/6041 - Release Date: 01/18/13 > > No virus found in this message. > Checked by AVG - www.avg.com > Version: 2013.0.2890 / Virus Database: 2639/6041 - Release Date: 01/18/13 > > ________________________________ > > No virus found in this message. > Checked by AVG - www.avg.com > Version: 2013.0.2890 / Virus Database: 2639/6045 - Release Date: 01/20/13 > > No virus found in this message. > Checked by AVG - www.avg.com > Version: 2013.0.2890 / Virus Database: 2639/6045 - Release Date: 01/20/13 -- http://ruchith.org --------------------------------------------------------------------- To unsubscribe, e-mail: java-dev-unsubscr...@axis.apache.org For additional commands, e-mail: java-dev-h...@axis.apache.org