This is how SAML Sender Vouches works and what we need to do in weblogic / java.
The short version is, the web service proxy client call the STS server to get an SAML assertion on behalf of the User to call the Web Service.
The long version, the user provides its credentials to the ws proxy client and the ws proxy client calls the STS server and provides the username / password of the user and the client key.
The STS validates the user and the ws proxy client certificate and the STS returns the STS identity assertion to the ws proxy client. The ws proxy client uses this STS assertion together with the ws client and ws server certificate to call the web service.
First we need to have 3 certificates, the first is alice, this will be used in the ws proxy client and the second certificate is bob, this will be used in the Weblogic web service server and the last we use wssipsts certificate for the Weblogic STS server. Add these keys into a java keystore.
Setting up the Secure Token Service (STS)
Create a new Weblogic 10.3.1 domain and start the admin server. First we need to enable SSL in the general tab of the server and then add our keystores in the keystore tab.
Provide the STS certificate alias, in my case wssipprv
Go the myrealm security where we add the Alice user and provide a password, Very important the username must match with the CN of the Alice certificate. The user provides the credentials and must match with user in WLS and the ws proxy client provides the Alice certificate and this must match with the PKI Credential mapping.
Go to the Credential mapping tab of the Provider tab and add a PKI Credential Mapping where we import the keystore and Add a SAML Credential Mapping version 2 where we add the Web Service URL.
Open the just created PKI credential mapping and add the keystore.
Next we open the SAML Credential Mapping version 2 and provide the Issuer URL and Name Qualifier.
Add the public key of the wssipsts
Add a WSS/Sender-Vouches Relying Party
Enable this and provide the target url of the Web Service Url and assign assertions and include key info
That is all for the STS server and now we can deploy the STS web service.
package nl.whitehorses.sts;
import weblogic.jws.Policy;
import weblogic.wsee.security.saml.SAMLTrustTokenProvider;
import weblogic.wsee.security.wst.framework.TrustTokenProviderRegistry;
import javax.jws.WebMethod;
import javax.jws.WebService;
@WebService
@Policy(uri="policy:Wssp1.2-2007-Wssc1.3-Bootstrap-Https-UNT.xml")
public class StsUnt {
static {
init();
}
@WebMethod
@Policy(uri="policy:Wssp1.2-2007-SignBody.xml")
public String dummyMethod(String s) {
return s;
}
static void init() {
TrustTokenProviderRegistry reg = TrustTokenProviderRegistry.getInstance();
SAMLTrustTokenProvider provider = new MySAMLTrustTokenProvider();
reg.registerProvider("http://docs.oasis-open.org/wss/2004/01/oasis-2004-01-saml-token-profile-1.0#SAMLAssertionID", provider);
reg.registerProvider("http://docs.oasis-open.org/wss/oasis-wss-saml-token-profile-1.0#SAMLAssertionID", provider);
reg.registerProvider("http://docs.oasis-open.org/wss/oasis-wss-saml-token-profile-1.1#SAMLV2.0", provider);
reg.registerProvider("http://docs.oasis-open.org/wss/oasis-wss-saml-token-profile-1.1#SAMLV1.0", provider);
reg.registerProvider("http://docs.oasis-open.org/wss/oasis-wss-saml-token-profile-1.1#SAMLV1.1", provider);
}
static class MySAMLTrustTokenProvider extends SAMLTrustTokenProvider {
}
}
Configure the Weblogic server for the Web Services
Create a new Weblogic domain and use the same keystore, we don't need to setup SSL on this server.
Go the myrealm security and go to providers tab where we add a new PKI Credential Mapping in the credentials tab. ( Use the same setting as the STS server )
We need to add 2 authentication providers and change the 2 default providers.
Create a SAML Authentication and SAML Identity Assertion provider.
Every authentication provider need to have the SUFFICIENT control flag.
Change the SAML Identity Assertion by adding an asserting party and the STS public certificate
Import the STS certificate
Change the just create Sender-Vouches asserting party. Enable this and provide the target url of the web service and add the issuer url, signature required and expect the STS certificate and allow virtual user.
Change the defaultIdentityAsserter and add wsse:PasswordDigest and X.509 as active types.
In the provider specific tab we need to set CN in the Default User Name Mapper Attribute Type and enable Use Default User Name Mapper.
In the DefaultAuthenticator we need to set control flag to SUFFICIENT
And in the provider specific tab. Enable Password Digests and Minimum Password Length to 1.
That's all for the Web Service server. Now we can deploy the webservice.
package nl.whitehorses.sts.ws;
import weblogic.jws.Policies;
import weblogic.jws.Policy;
import javax.jws.WebService;
@Policies(
{
@Policy(uri = "policy:Wssp1.2-2007-Saml1.1-SenderVouches-Wss1.0.xml"),
@Policy(uri = "policy:Wssp1.2-2007-SignBody.xml"),
@Policy(uri = "policy:Wssp1.2-2007-EncryptBody.xml")
}
)
@WebService
public class EchoService {
public String echo( String hello){
return hello;
}
}
Generating the Web Service Proxy Client
The last step we need to generate a web service proxy client and add the username and the client credentials mappings.
package nl.whitehorses.sts.ws.client;
import java.io.InputStream;
import java.io.ByteArrayInputStream;
import java.security.cert.X509Certificate;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.net.URL;
import javax.xml.namespace.QName;
import javax.xml.ws.BindingProvider;
import javax.xml.ws.WebServiceRef;
import weblogic.security.SSL.TrustManager;
import weblogic.wsee.message.WlMessageContext;
import weblogic.wsee.security.bst.ClientBSTCredentialProvider;
import weblogic.wsee.security.saml.SAMLTrustCredentialProvider;
import weblogic.wsee.security.unt.ClientUNTCredentialProvider;
import weblogic.xml.crypto.wss.WSSecurityContext;
import weblogic.xml.crypto.wss.provider.CredentialProvider;
public class EchoServicePortClient
{
@WebServiceRef
private static EchoServiceService echoServiceService;
private static String stsUntPolicy =
"<?xml version=\"1.0\"?>\n" +
"<wsp:Policy\n" +
" xmlns:wsp=\"http://schemas.xmlsoap.org/ws/2004/09/policy\"\n" +
" xmlns:sp=\"http://docs.oasis-open.org/ws-sx/ws-securitypolicy/200702\"\n" +
" >\n" +
" <sp:TransportBinding>\n" +
" <wsp:Policy>\n" +
" <sp:TransportToken>\n" +
" <wsp:Policy>\n" +
" <sp:HttpsToken/>\n" +
" </wsp:Policy>\n" +
" </sp:TransportToken>\n" +
" <sp:AlgorithmSuite>\n" +
" <wsp:Policy>\n" +
" <sp:Basic256/>\n" +
" </wsp:Policy>\n" +
" </sp:AlgorithmSuite>\n" +
" <sp:Layout>\n" +
" <wsp:Policy>\n" +
" <sp:Lax/>\n" +
" </wsp:Policy>\n" +
" </sp:Layout>\n" +
" <sp:IncludeTimestamp/>\n" +
" </wsp:Policy>\n" +
" </sp:TransportBinding>\n" +
" <sp:SupportingTokens>\n" +
" <wsp:Policy>\n" +
" <sp:UsernameToken\n" +
" sp:IncludeToken=\"http://docs.oasis-open.org/ws-sx/ws-securitypolicy/200702/IncludeToken/AlwaysToRecipient\">\n" +
" <wsp:Policy>\n" +
" <sp:WssUsernameToken10/>\n" +
" </wsp:Policy>\n" +
" </sp:UsernameToken>\n" +
" </wsp:Policy>\n" +
" </sp:SupportingTokens>\n" +
"</wsp:Policy>";
public static void main(String[] args) {
System.setProperty("com.sun.xml.ws.transport.http.client.HttpTransportPipe.dump", "true");
try {
String wsURL = "http://10.10.10.10:7011/saml-ws-context-root/EchoServicePort?WSDL";
echoServiceService = new EchoServiceService( new URL(wsURL)
, new QName("http://ws.sts.whitehorses.nl/", "EchoServiceService"));
EchoService echoService = echoServiceService.getEchoServicePort();
System.setProperty("javax.net.ssl.trustStore", "C:/projecten/workspace/11g_prod/saml1.1_ws/wsttest1/certs/cacerts");
Map<String, Object> requestContext = ((BindingProvider)echoService).getRequestContext();
List<CredentialProvider> credList = new ArrayList<CredentialProvider>();
// Add the necessary credential providers to the list
InputStream policy = new ByteArrayInputStream(stsUntPolicy.getBytes("UTF-8"));
requestContext.put(WlMessageContext.WST_BOOT_STRAP_POLICY, policy );
String stsURL = "https://localhost:7022/sts/StsUntPort";
requestContext.put(WlMessageContext.STS_ENDPOINT_ADDRESS_PROPERTY, stsURL);
requestContext.put(WSSecurityContext.TRUST_MANAGER,
new TrustManager() {
public boolean certificateCallback(X509Certificate[] chain, int validateErr) {
// need to validate if the server cert can be trusted
return true;
}
});
credList.add(new SAMLTrustCredentialProvider());
String username = "Alice";
String password = "weblogic1";
credList.add(new ClientUNTCredentialProvider(username.getBytes(), password.getBytes()));
// ClientBSTCredentialProvider
String defaultClientcert = "C:/projecten/workspace/11g_prod/saml1.1_ws/wsttest1/certs/Alice.cer";
String clientcert = System.getProperty("target.clientcert", defaultClientcert);
String defaultClientkey = "C:/projecten/workspace/11g_prod/saml1.1_ws/wsttest1/certs/Alice.prv";
String clientkey = System.getProperty("target.clientkey", defaultClientkey);
String defaultServerCert = "C:/projecten/workspace/11g_prod/saml1.1_ws/wsttest1/certs/Bob.cer";
String serverCert = System.getProperty("target.serverCert", defaultServerCert);
credList.add(new ClientBSTCredentialProvider(clientcert, clientkey, serverCert));
requestContext.put(WSSecurityContext.CREDENTIAL_PROVIDER_LIST, credList);
// Add your code to call the desired methods.
System.out.println(echoService.echo("Hello"));
} catch (Exception ex) {
ex.printStackTrace();
}
}
}