Hello Sergey,
i think i found the cause of the problem. JBoss 6.0.0.Final comes with CXF
2.3.1. However, i checked out the 2.3.3 tag and did a little bug fix.
What do you think of it? Please tell me, if you will make a fix for 2.3.x, then
i would like to download the update.
Please look at
org.apache.cxf.ws.security.wss4j.WSS4JInInterceptor.doResults()
At the end of the method is a for-loop over the wssEngineResults. If
withCallbacks is false then the UsernameToken should be put in the message. The
Problem is, the first Principal found is not the UsernameTokenPrincipal but the
DerivedKeyPrincipal. This triggers creation of a security context and breakes
the for-loop. The second wssEngineResult would have been the
UsernameTokenPrincipal.
I believe this is the reason why i receive the error message:
Security Token is not available on the current message
Here is the patch i use. It seems to work for me.
David
protected void doResults(SoapMessage msg, String actor, SOAPMessage doc, Vector
wsResult,
boolean utWithCallbacks) throws SOAPException, XMLStreamException,
WSSecurityException {
/*
* All ok up to this point. Now construct and setup the security result
* structure. The service may fetch this and check it.
*/
List<Object> results =
CastUtils.cast((List)msg.get(WSHandlerConstants.RECV_RESULTS));
if (results == null) {
results = new Vector<Object>();
msg.put(WSHandlerConstants.RECV_RESULTS, results);
}
WSHandlerResult rResult = new WSHandlerResult(actor, wsResult);
results.add(0, rResult);
SOAPBody body = doc.getSOAPBody();
XMLStreamReader reader = StaxUtils.createXMLStreamReader(new
DOMSource(body));
// advance just past body
int evt = reader.next();
int i = 0;
while (reader.hasNext() && i < 1
&& (evt != XMLStreamConstants.END_ELEMENT || evt !=
XMLStreamConstants.START_ELEMENT)) {
reader.next();
i++;
}
msg.setContent(XMLStreamReader.class, reader);
String pwType = (String)getProperty(msg, "passwordType");
if ("PasswordDigest".equals(pwType)) {
//CXF-2150 - we need to check the UsernameTokens
for (WSSecurityEngineResult o : CastUtils.cast(wsResult,
WSSecurityEngineResult.class)) {
Integer actInt =
(Integer)o.get(WSSecurityEngineResult.TAG_ACTION);
if (actInt == WSConstants.UT) {
WSUsernameTokenPrincipal princ
=
(WSUsernameTokenPrincipal)o.get(WSSecurityEngineResult.TAG_PRINCIPAL);
if (!princ.isPasswordDigest()) {
LOG.warning("Non-digest UsernameToken found, but digest
required");
throw new
WSSecurityException(WSSecurityException.INVALID_SECURITY);
}
}
}
}
if (!utWithCallbacks) {
for (WSSecurityEngineResult o : CastUtils.cast(wsResult,
WSSecurityEngineResult.class)) {
final Principal p =
(Principal)o.get(WSSecurityEngineResult.TAG_PRINCIPAL);
if (p instanceof WSUsernameTokenPrincipal) {
msg.put(PRINCIPAL_RESULT, p);
WSS4JTokenConverter.convertToken(msg, p);
SecurityContext sc = msg.get(SecurityContext.class);
if (sc == null || sc.getUserPrincipal() == null) {
msg.put(SecurityContext.class,
createSecurityContext(p));
}
break;
}
}
} else {
for (WSSecurityEngineResult o : CastUtils.cast(wsResult,
WSSecurityEngineResult.class)) {
final Principal p =
(Principal)o.get(WSSecurityEngineResult.TAG_PRINCIPAL);
if (p != null) {
msg.put(PRINCIPAL_RESULT, p);
if (!utWithCallbacks) {
WSS4JTokenConverter.convertToken(msg, p);
}
SecurityContext sc = msg.get(SecurityContext.class);
if (sc == null || sc.getUserPrincipal() == null) {
msg.put(SecurityContext.class,
createSecurityContext(p));
break;
}
}
}
}
}
-----Ursprüngliche Nachricht-----
From: Sergey Beryozkin
Sent: Monday, April 04, 2011 1:50 PM
To: [email protected]
Cc: David Zhang
Subject: Re: UsernameToken JBoss Integration
Sorry, that one is indeed needed for the encryption itself to succeed.
Can you try, for the sake of the test, send unencrypted UTs ?
I don't recall if I had the test for the case when the body was also
encrypted, would have to check.
In meantime, you may want to try the following:
- if UT passwords are not encrypted then simply register a CXF interceptor,
after WSS4JInInterceptor, extract a WSS4J token and use it to create the
Subject and then replace the existing SecurityContext on the message with
the new one - if you decide to follow this route then I can provide more
info on how existing CXF SecurityContext impls can be reused
- if it is not a WSDL-first case then register an
AbstractUsernameTokenAuthenticatingInterceptor implementation instead of
WSS4InInterceptor but configure it as usual, just do not provide a UT
callback
Let us know how it goes
Sergey
On Mon, Apr 4, 2011 at 12:33 PM, David Zhang <[email protected]> wrote:
> Hello,
>
> i still cannot get the AuthenticationInterceptor to work.
>
> The password callback is needed to retrieve the password for the private
> key. Otherwise the server cannot decrypt the SOAP Request.
>
> However, when the AuthenticationInterceptor is called in the pre-invoke
> Phase, the security token is null.
> see AbstractSecurityContextInInterceptor.handleMessage()
>
> Any ideas?
>
> David
>
> From: [email protected]
> Sent: Friday, April 01, 2011 7:38 AM
> To: [email protected]
> Subject: Re: UsernameToken JBoss Integration
>
> Hello Sergey,
>
> if i remove the password callback, i get another error message:
> General security error (WSSecurityEngine: Callback supplied no password
> for: myAlias)
>
> The keystore.properties file contains only the password for the keystore,
> not for the private key inside the keystore. Also i can not find a way to
> create a private key without password by the java keytool.
>
> Is there another way to provide the password besides the password callback?
> Is there maybe a property in the keystore.properties file? I cannot find a
> suitable property in this list:
> http://cxf.apache.org/docs/ws-securitypolicy.html
>
> This is the content of the keystore.properties. The ${}-parts are replaced
> by maven with actual values:
>
>
>
> org.apache.ws.security.crypto.provider=org.apache.ws.security.components.crypto.Merlin
> org.apache.ws.security.crypto.merlin.keystore.type=jks
> org.apache.ws.security.crypto.merlin.keystore.password=${keystore.password}
> org.apache.ws.security.crypto.merlin.keystore.alias=${certificate.alias}
> org.apache.ws.security.crypto.merlin.file=${keystore.path}
>
>
>
> Thank you
> David
>
> -----Ursprüngliche Nachricht-----
> From: Sergey Beryozkin
> Sent: Thursday, March 31, 2011 10:21 PM
> To: [email protected]
> Subject: Re: UsernameToken JBoss Integration
>
> Hi -
>
> You don't need a password callback in this case.
>
> Cheers, Sergey
>
> On Thu, Mar 31, 2011 at 7:42 PM, David Zhang <[email protected]> wrote:
>
> > Hi Sergey,
> >
> > thank you very much for taking the time to help me.
> > I have set the property you mentioned. Look, this is my configuration:
> >
> >
> > <jaxws:endpoint id="SecureServiceBean"
> >
> > address="/example-ejb/SecureService"
> >
> > implementor="com.example.SecureServiceBean">
> >
> > <jaxws:invoker>
> >
> > <bean class="org.jboss.wsf.stack.cxf.InvokerEJB3" />
> >
> > </jaxws:invoker>
> >
> > <jaxws:inInterceptors>
> >
> >
> > <bean class="com.example.AuthenticationInterceptor1"/>
> >
> > </jaxws:inInterceptors>
> >
> > <jaxws:properties>
> >
> > <entry key="ws-security.ut.no-callbacks" value="true" />
> >
> > <!--<entry key="ws-security.validate.token" value="false" />-->
> >
> > <entry key="ws-security.signature.properties" value="keystore.properties"
> > />
> >
> > <entry key="ws-security.encryption.properties"
> value="keystore.properties"
> > />
> >
> > <entry key="ws-security.callback-handler"
> > value="com.example.PasswordCallback" />
> >
> > </jaxws:properties>
> >
> > </jaxws:endpoint>
> >
> > Where com.example.AuthenticationInterceptor1 extends
> > AbstractUsernameTokenInInterceptor.
> > This results in:
> > 12:01:12,770 ERROR
> >
> [org.apache.cxf.interceptor.security.AbstractSecurityContextInInterceptor]
> > Security Token is not available on the current message
> >
> > Thanks
> > David
> >
> >
> > -----Ursprüngliche Nachricht-----
> > From: Sergey Beryozkin
> > Sent: Thursday, March 31, 2011 11:06 AM
> > To: [email protected]
> > Subject: Re: UsernameToken JBoss Integration
> >
> > Hi
> >
> > Please check this section:
> >
> >
> >
> http://cxf.apache.org/docs/security.html#Security-WSSecurityUsernameTokenandCustomAuthentication
> >
> > In 2.3.x you have to set a "ws-security.ut.no-callbacks" property and
> this
> > will ensure AbstractUserNameTokenInterceptor can be used.
> >
> > Setting this property results in WSS4JInInterceptor duplicating WSS4J
> > specific UT into CXF specific UsernameToken which is what
> > AbstractUserNameTokenInterceptor is checking.
> >
> > Cheers, Sergey
> >
> > On Thu, Mar 31, 2011 at 8:42 AM, David Zhang <[email protected]>
> wrote:
> >
> > >
> > > Hello,
> > >
> > >
> > >
> > > i have a web service with symmetric binding and self-signed server
> > > certificate.
> > >
> > > I implemented a password callbackhandler for the password to the
> private
> > > key of the server.
> > >
> > > Now i want to add authentication with username token. So i added a
> > > supporting token to the ws security policy.
> > >
> > >
> > >
> > > To this point everything works fine. The server gets an encrypted
> request
> > > with a username token.
> > >
> > > My concern is that i do not want to do the authentication in my
> > > application. I want to integrate the username token with JBoss
> Security.
> > >
> > >
> > >
> > > So i followed these instructions:
> > >
> >
> http://community.jboss.org/wiki/JBossWS-StackCXFUserGuide#Authentication_and_authorization
> > >
> > > However, it did not work. I used a debugger to check and i saw the
> > > authentication interceptor was created when my app was deployed but it
> > was
> > > never called on a client request.
> > >
> > >
> > >
> > > Later i found this:
> > >
> >
> http://svn.apache.org/repos/asf/cxf/tags/cxf-2.3.3/systests/ws-specs/src/test/java/org/apache/cxf/systest/ws/wssec10/server/SimpleSubjectCreatingInterceptor.java
> > >
> > > I implemented an interceptor following that example. I put a breakpoint
> > on
> > > the createSubject method. It was never called.
> > >
> > >
> > >
> > > Then i followed this example:
> > >
> >
> http://svn.apache.org/repos/asf/cxf/tags/cxf-2.3.3/systests/ws-specs/src/test/java/org/apache/cxf/systest/ws/wssec10/server/SimpleUsernameTokenInterceptor.java
> > >
> > > At least i know this interceptor was called. But it produced an error
> > > before the createSubject method was called. The error says: Security
> > Token
> > > is not available on the current message
> > >
> > >
> > >
> > > But this can not be true. Because then i removed the interceptor
> removed
> > > the property ws-security.ut.no-callbacks and on the next request my
> > password
> > > callbackhandler was called with the username i set on the client.
> > >
> > >
> > >
> > > Please, can anybody explain me what i am doing wrong?
> > >
> > >
> > >
> > > Thanks
> > >
> > > David
> > >
> >
> >
> >
> >
> > --
> > Sergey Beryozkin
> >
> > Application Integration Division of Talend <http://www.talend.com>
> > http://sberyozkin.blogspot.com
>
>
>
>
> --
> Sergey Beryozkin
>
> Application Integration Division of Talend <http://www.talend.com>
> http://sberyozkin.blogspot.com
>
--
Sergey Beryozkin
Application Integration Division of Talend <http://www.talend.com>
http://sberyozkin.blogspot.com