Suponiendo una llamada webservice que contenga una Assertion SAML firmada, como verificamos esa firma? CXF provee "interceptores" para incluir código antes y después de una invocación a webservice.
Primero debemos configurar (con Spring en este caso) la invocación:
<jaxws:client id="clientWS" serviceClass="es.mycompany.MyService" address="http://localhost:8080/app/services/myservice"> <jaxws:dataBinding> <ref bean="aegisBean" /> </jaxws:dataBinding> <jaxws:inInterceptors> <ref bean="clientWS.InInterceptor" /> </jaxws:inInterceptors> </jaxws:client> <bean id="clientWS.InInterceptor" class="es.mycompany.MyInterceptor"> <constructor-arg> <map> <entry key="action" value="Timestamp Signature"/> <entry key="passwordCallbackClass" value="es.mycompany.MyPasswordCallback"/> <entry key="signaturePropFile" value="keystore.properties"/> </map> </constructor-arg> </bean>
Luego creamos nuestro fichero de propiedades del keystore ("keystore.properties"):
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.alias=MyAlias org.apache.ws.security.crypto.merlin.keystore.password=MyPassword org.apache.ws.security.crypto.merlin.file=keystore.jks
Y finalmente la clase encargada de dar las contraseñas de acceso a los certificados. Esta clase es claramente mejorable, pero sirve como ejemplo:
public class MyPasswordCallback implements CallbackHandler { private MapTeniendo todo configurado, solo nos queda el código del interceptor, que a su vez se apoya en una clase de utilidades:passwords = new HashMap (); public STSPasswordCallback() { passwords.put("MyAlias", "MyPassword"); } public void handle(Callback[] callbacks) throws IOException, UnsupportedCallbackException { for (int i = 0; i < callbacks.length; i++) { WSPasswordCallback pc = (WSPasswordCallback) callbacks[i]; String pass = passwords.get(pc.getIdentifier()); if (pass != null) { pc.setPassword(pass); return; } } } }
public class MyInterceptor extends WSS4JInInterceptor { private String issuer = "http://www.mycompany.com"; public MyInterceptor() { super(); } public MyInterceptor(MapComo ven, todo el trabajo lo hace la línea trustEngine.validate(assertion.getSignature(), criteriaSet);, solo hay que llegar hasta ella con los datos adecuados.properties) { super(properties); } protected void doReceiverAction(int doAction, RequestData reqData) throws WSSecurityException { // Get SOAP Header SOAPMessage message = ((org.apache.cxf.binding.soap.SoapMessage) reqData.getMsgContext()).getContent(javax.xml.soap.SOAPMessage.class); SOAPHeader soapHeader = message.getSOAPHeader(); // Get Assertion XML XPathUtils xu = new XPathUtils(); Element xmlAssertion = (Element) xu.getValueNode("//saml2:Assertion", soapHeader); // Unmarshall Unmarshaller unmarshaller = unmarshallerFactory.getUnmarshaller(xmlAssertion); Assertion assertion = (Assertion) unmarshaller.unmarshall(xmlAssertion); // Get Handler properties String sigPropFile = getString(WSHandlerConstants.SIG_PROP_FILE, reqData.getMsgContext()); String callback = getString(WSHandlerConstants.PW_CALLBACK_CLASS, reqData.getMsgContext()); // Verify SAMLUtils.verifySignature(assertion, issuer, sigPropFile, callback); super.doReceiverAction(doAction, reqData); } public void handleMessage(SoapMessage message) throws Fault { super.handleMessage(message); } } public class SAMLUtils { public static void verifySignature(Assertion assertion, String issuer, String sigPropFile, String callback) throws WSSecurityException { X509Credential cred = getX509Credential(sigPropFile, callback); StaticCredentialResolver credResolver = new StaticCredentialResolver(cred); KeyInfoCredentialResolver kiResolver = SecurityHelper.buildBasicInlineKeyInfoResolver(); ExplicitKeySignatureTrustEngine trustEngine = new ExplicitKeySignatureTrustEngine(credResolver, kiResolver); CriteriaSet criteriaSet = new CriteriaSet(); criteriaSet.add(new EntityIDCriteria(issuer)); criteriaSet.add(new UsageCriteria(UsageType.SIGNING)); criteriaSet.add(new MetadataCriteria(IDPSSODescriptor.DEFAULT_ELEMENT_NAME, SAMLConstants.SAML20P_NS)); try { trustEngine.validate(assertion.getSignature(), criteriaSet); } catch (SecurityException e) { throw new WSSecurityException(e.getMessage()); } } public static X509Credential getX509Credential(String sigPropFile, String callback) throws WSSecurityException { PrivateKey privateKey = null; X509Certificate[] certs = null; Crypto crypto = crypto = CryptoFactory.getInstance(sigPropFile); try { CallbackHandler cbhandler = getPasswordCallBack(callback); WSPasswordCallback cb = new WSPasswordCallback(crypto.getDefaultX509Alias(), WSPasswordCallback.SIGNATURE); cbhandler.handle(new Callback[] { cb }); privateKey = crypto.getPrivateKey(crypto.getDefaultX509Alias(), cb.getPassword()); certs = crypto.getCertificates(crypto.getDefaultX509Alias()); } catch (Exception e) { throw new WSSecurityException(e.getMessage()); } if (certs.length != 1) { throw new WSSecurityException("Couldn't get the (" + crypto.getDefaultX509Alias() + ") signature certificate."); } X509Credential cred = SecurityHelper.getSimpleCredential(certs[0], privateKey); return cred; } public static CallbackHandler getPasswordCallBack(String callback) throws WSSecurityException { CallbackHandler cbHandler = null; try { Class cbClass = Loader.loadClass(callback); cbHandler = (CallbackHandler) cbClass.newInstance(); } catch (Exception e) { throw new WSSecurityException("WSHandler: cannot create instance of password callback: " + callback, e); } return cbHandler; } }
No hay comentarios:
Publicar un comentario