Good day, I am dusting off my CXF after many years, trying to replace a Weblogic SAML implementation with CXF.
I’ve been trying out a WS-SecurityPolicy-described SAML invocation hello world using some of the CXF systest code as the basis of my example. This is an asymmetric sender-vouches call. I’ve noticed that the WebServiceContext in the service, when I call getUserPrincipal() always returns me the x509 signature subject for the message (alice), and never the SAML Subject Name that’s created on the client callback (uid=sts-client,o=mock-sts.com <http://mock-sts.com/>). Is this as designed? Looking at the WSS4J and CXF code, I have seen code paths that do create a Principal based on the SAML Subject but it seems this never gets called if the signature principal is already set. I’ve tried a variety of approaches but my unfamiliarity with CXF is showing. My only current thought is that I could workaround this by turning off token validation and building a custom JAAS SAML Login Module that validates the token and processes the login (similar to how WebLogic does it with its SAML Identity Asserter), but wanted to see if there was a more effective approach. Thanks, Stu Here are my code snippets. Client: @Configuration @EnableAutoConfiguration @SpringBootApplication public class Application { public static void main(String[] args) { ApplicationContext ctx = SpringApplication.run(Application.class, args); } @Bean public HelloWorld helloService() { JaxWsProxyFactoryBean factory = new JaxWsProxyFactoryBean(); factory.setWsdlLocation("classpath:wsdl/hello.wsdl"); factory.setAddress("http://myserver/ws-server-1.0/api/hello"); factory.setServiceName(QName.valueOf("{http://service.spring.demo/}HelloWorldImplService")); factory.setEndpointName(QName.valueOf("{http://service.spring.demo/}HelloWorldImplPort")); factory.setServiceClass(HelloWorld.class); Map<String, Object> props = new HashMap<String, Object>(); props.put("ws-security.callback-handler", new KeystoreCallbackHandler()); props.put("ws-security.signature.username", "alice"); props.put("ws-security.signature.properties", "alice.properties"); props.put("ws-security.saml-callback-handler", new demo.spring.service.SamlCallbackHandler()); factory.setProperties(props); HelloWorld client = (HelloWorld) factory.create(); return client; } } Client Callback (similar to systest callback): public void handle(Callback[] callbacks) throws IOException, UnsupportedCallbackException { // snip callback.setIssuer("sts"); String subjectName = "uid=sts-client,o=mock-sts.com"; String subjectQualifier = "www.mock-sts.com"; if (!saml2 && SAML2Constants.CONF_SENDER_VOUCHES.equals(confirmationMethod)) { confirmationMethod = SAML1Constants.CONF_SENDER_VOUCHES; } SubjectBean subjectBean = new SubjectBean( subjectName, subjectQualifier, confirmationMethod ); callback.setSubject(subjectBean); try { Crypto crypto = CryptoFactory.getInstance(cryptoPropertiesFile); callback.setIssuerCrypto(crypto); callback.setIssuerKeyName(cryptoAlias); callback.setIssuerKeyPassword(cryptoPassword); callback.setSignAssertion(signAssertion); } catch (WSSecurityException e) { throw new IOException(e); } } Service: @WebService(endpointInterface = "demo.spring.service.HelloWorld") public class HelloWorldImpl implements HelloWorld { @Resource WebServiceContext wsContext; public String sayHi(String text) { Principal pr = wsContext.getUserPrincipal(); String username = ""; if (pr != null) username = pr.getName(); System.out.println("sayHi called"); return "Ping " + username + " - " + text; } } This always prints “Ping
