Commit 417dc715 authored by benjamin.ertl's avatar benjamin.ertl
Browse files

add saml client

parent dd2a57c8
...@@ -111,6 +111,17 @@ ...@@ -111,6 +111,17 @@
</dependency> </dependency>
<!-- SAML --> <!-- SAML -->
<dependency>
<groupId>org.opensaml</groupId>
<artifactId>opensaml</artifactId>
<version>2.6.4</version>
<exclusions>
<exclusion>
<groupId>org.slf4j</groupId>
<artifactId>log4j-over-slf4j</artifactId>
</exclusion>
</exclusions>
</dependency>
<!-- Utils --> <!-- Utils -->
<dependency> <dependency>
......
package edu.kit.scc; package edu.kit.scc;
import java.io.ByteArrayInputStream;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.io.RandomAccessFile;
import java.io.StringWriter;
import java.nio.charset.StandardCharsets;
import java.security.KeyFactory;
import java.security.NoSuchAlgorithmException;
import java.security.PrivateKey;
import java.security.cert.Certificate;
import java.security.cert.CertificateException;
import java.security.cert.CertificateFactory;
import java.security.cert.X509Certificate;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.PKCS8EncodedKeySpec;
import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Map;
import javax.xml.transform.Result;
import javax.xml.transform.Source;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerConfigurationException;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
import org.apache.commons.httpclient.UsernamePasswordCredentials;
import org.apache.commons.httpclient.auth.AuthScope;
import org.apache.commons.ssl.X509CertificateChainBuilder;
import org.joda.time.DateTime;
import org.opensaml.DefaultBootstrap;
import org.opensaml.common.SAMLVersion;
import org.opensaml.saml2.core.AttributeQuery;
import org.opensaml.saml2.core.Issuer;
import org.opensaml.saml2.core.NameID;
import org.opensaml.saml2.core.Response;
import org.opensaml.saml2.core.Subject;
import org.opensaml.ws.soap.client.BasicSOAPMessageContext;
import org.opensaml.ws.soap.client.http.HttpClientBuilder;
import org.opensaml.ws.soap.client.http.HttpSOAPClient;
import org.opensaml.ws.soap.common.SOAPException;
import org.opensaml.ws.soap.soap11.Body;
import org.opensaml.ws.soap.soap11.Envelope;
import org.opensaml.xml.Configuration;
import org.opensaml.xml.ConfigurationException;
import org.opensaml.xml.XMLObject;
import org.opensaml.xml.XMLObjectBuilderFactory;
import org.opensaml.xml.io.Marshaller;
import org.opensaml.xml.io.MarshallerFactory;
import org.opensaml.xml.io.MarshallingException;
import org.opensaml.xml.parse.BasicParserPool;
import org.opensaml.xml.security.SecurityException;
import org.opensaml.xml.security.SecurityHelper;
import org.opensaml.xml.security.keyinfo.KeyInfoGenerator;
import org.opensaml.xml.security.x509.BasicX509Credential;
import org.opensaml.xml.security.x509.X509KeyInfoGeneratorFactory;
import org.opensaml.xml.signature.KeyInfo;
import org.opensaml.xml.signature.Signature;
import org.opensaml.xml.signature.SignatureConstants;
import org.opensaml.xml.util.XMLHelper;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.BeanFactory; import org.springframework.beans.factory.BeanFactory;
...@@ -17,12 +79,15 @@ import org.springframework.core.io.Resource; ...@@ -17,12 +79,15 @@ import org.springframework.core.io.Resource;
import org.springframework.ldap.core.ContextSource; import org.springframework.ldap.core.ContextSource;
import org.springframework.ldap.core.LdapTemplate; import org.springframework.ldap.core.LdapTemplate;
import org.springframework.ldap.core.support.LdapContextSource; import org.springframework.ldap.core.support.LdapContextSource;
import org.w3c.dom.Element;
import edu.kit.scc.dao.UserDAO; import edu.kit.scc.dao.UserDAO;
import edu.kit.scc.dto.UserDTO; import edu.kit.scc.dto.UserDTO;
import edu.kit.scc.http.HttpClient; import edu.kit.scc.http.HttpClient;
import edu.kit.scc.http.HttpResponse; import edu.kit.scc.http.HttpResponse;
import edu.kit.scc.ldap.LDAPUserDAO; import edu.kit.scc.ldap.LDAPUserDAO;
import edu.kit.scc.saml.HttpSignableSoapClient;
import edu.kit.scc.saml.SamlClient;
public class Main { public class Main {
...@@ -54,7 +119,9 @@ public class Main { ...@@ -54,7 +119,9 @@ public class Main {
return ldapUserDAO; return ldapUserDAO;
} }
public static void main(String[] args) { public static void main(String[] args) throws ConfigurationException, MarshallingException, TransformerException,
CertificateException, javax.security.cert.CertificateException, IOException, NoSuchAlgorithmException,
InvalidKeySpecException, SecurityException, SOAPException {
// OidcClient oidcClient = new OidcClient(clientId, clientSecret, // OidcClient oidcClient = new OidcClient(clientId, clientSecret,
// redirectUri, oidcTokenEndpoint, // redirectUri, oidcTokenEndpoint,
...@@ -83,20 +150,27 @@ public class Main { ...@@ -83,20 +150,27 @@ public class Main {
// ApplicationContext ctx = new // ApplicationContext ctx = new
// ClassPathXmlApplicationContext("springldap.xml"); // ClassPathXmlApplicationContext("springldap.xml");
ApplicationContext ctx = new AnnotationConfigApplicationContext(Main.class); // ApplicationContext ctx = new
UserDAO ldapUser = (LDAPUserDAO) ctx.getBean("ldapUser"); // AnnotationConfigApplicationContext(Main.class);
List<UserDTO> userList = ldapUser.getAllUserNames(); // UserDAO ldapUser = (LDAPUserDAO) ctx.getBean("ldapUser");
for (int i = 0; i < userList.size(); i++) // List<UserDTO> userList = ldapUser.getAllUserNames();
log.info("User name {}", ((UserDTO) userList.get(i)).getCommonName()); // for (int i = 0; i < userList.size(); i++)
List<UserDTO> userDetails = ldapUser.getUserDetails("John Smith", "Smith"); // log.info("User name {}", ((UserDTO)
for (int i = 0; i < userDetails.size(); i++) // userList.get(i)).getCommonName());
log.info("Description {}", ((UserDTO) userDetails.get(i)).getDescription()); // List<UserDTO> userDetails = ldapUser.getUserDetails("John Smith",
// "Smith");
UserDTO newUser = new UserDTO(); // for (int i = 0; i < userDetails.size(); i++)
newUser.setCommonName("me"); // log.info("Description {}", ((UserDTO)
newUser.setLastName("too"); // userDetails.get(i)).getDescription());
ldapUser.insertUser(newUser); //
// UserDTO newUser = new UserDTO();
((AbstractApplicationContext) ctx).close(); // newUser.setCommonName("me");
// newUser.setLastName("too");
// ldapUser.insertUser(newUser);
//
// ((AbstractApplicationContext) ctx).close();
SamlClient client = new SamlClient();
client.attributeQuery("ym0762", "oo22-.22", "MdWhcFYwml0vPFMscox33AYkkgs=", "https://ldf.data.kit.edu/sp");
} }
} }
package edu.kit.scc.saml;
import java.io.ByteArrayOutputStream;
import java.io.OutputStreamWriter;
import java.io.Serializable;
import java.nio.charset.Charset;
import org.apache.commons.httpclient.HttpClient;
import org.apache.commons.httpclient.cookie.CookiePolicy;
import org.apache.commons.httpclient.methods.ByteArrayRequestEntity;
import org.apache.commons.httpclient.methods.PostMethod;
import org.apache.commons.httpclient.methods.RequestEntity;
import org.opensaml.ws.soap.client.SOAPClientException;
import org.opensaml.ws.soap.client.http.HttpSOAPClient;
import org.opensaml.ws.soap.client.http.HttpSOAPRequestParameters;
import org.opensaml.ws.soap.soap11.Envelope;
import org.opensaml.xml.Configuration;
import org.opensaml.xml.io.Marshaller;
import org.opensaml.xml.io.MarshallingException;
import org.opensaml.xml.parse.ParserPool;
import org.opensaml.xml.signature.Signature;
import org.opensaml.xml.signature.SignatureException;
import org.opensaml.xml.signature.Signer;
import org.opensaml.xml.util.XMLHelper;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.w3c.dom.Element;
public class HttpSignableSoapClient extends HttpSOAPClient implements Serializable {
private static final long serialVersionUID = 1L;
private static Logger logger = LoggerFactory.getLogger(HttpSignableSoapClient.class);
private Signature signature;
public HttpSignableSoapClient(HttpClient client, ParserPool parser, Signature signature) {
super(client, parser);
this.signature = signature;
}
@Override
protected RequestEntity createRequestEntity(Envelope message, Charset charset) throws SOAPClientException {
try {
Marshaller marshaller = Configuration.getMarshallerFactory().getMarshaller(message);
ByteArrayOutputStream arrayOut = new ByteArrayOutputStream();
OutputStreamWriter writer = new OutputStreamWriter(arrayOut, charset);
Element element = marshaller.marshall(message);
try {
Signer.signObject(signature);
} catch (SignatureException e) {
throw new SOAPClientException(e);
}
if (logger.isDebugEnabled()) {
logger.debug("Outbound SOAP message is:\n" + XMLHelper.prettyPrintXML(element));
}
XMLHelper.writeNode(element, writer);
return new ByteArrayRequestEntity(arrayOut.toByteArray(), "text/xml");
} catch (MarshallingException e) {
throw new SOAPClientException("Unable to marshall SOAP envelope", e);
}
}
}
package edu.kit.scc.saml;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.RandomAccessFile;
import java.io.StringWriter;
import java.security.KeyFactory;
import java.security.NoSuchAlgorithmException;
import java.security.PrivateKey;
import java.security.cert.CertificateException;
import java.security.cert.CertificateFactory;
import java.security.cert.X509Certificate;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.PKCS8EncodedKeySpec;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.xml.transform.Result;
import javax.xml.transform.Source;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerConfigurationException;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
import org.apache.commons.httpclient.Cookie;
import org.apache.commons.httpclient.HttpState;
import org.apache.commons.httpclient.UsernamePasswordCredentials;
import org.apache.commons.httpclient.auth.AuthScope;
import org.joda.time.DateTime;
import org.opensaml.DefaultBootstrap;
import org.opensaml.common.SAMLVersion;
import org.opensaml.common.impl.SecureRandomIdentifierGenerator;
import org.opensaml.common.xml.SAMLConstants;
import org.opensaml.saml2.core.AttributeQuery;
import org.opensaml.saml2.core.AuthnRequest;
import org.opensaml.saml2.core.Issuer;
import org.opensaml.saml2.core.NameID;
import org.opensaml.saml2.core.NameIDPolicy;
import org.opensaml.saml2.core.Response;
import org.opensaml.saml2.core.Subject;
import org.opensaml.ws.soap.client.BasicSOAPMessageContext;
import org.opensaml.ws.soap.client.http.HttpClientBuilder;
import org.opensaml.ws.soap.client.http.HttpSOAPClient;
import org.opensaml.ws.soap.common.SOAPException;
import org.opensaml.ws.soap.soap11.Body;
import org.opensaml.ws.soap.soap11.Envelope;
import org.opensaml.xml.Configuration;
import org.opensaml.xml.ConfigurationException;
import org.opensaml.xml.XMLObject;
import org.opensaml.xml.XMLObjectBuilderFactory;
import org.opensaml.xml.io.Marshaller;
import org.opensaml.xml.io.MarshallerFactory;
import org.opensaml.xml.io.MarshallingException;
import org.opensaml.xml.parse.BasicParserPool;
import org.opensaml.xml.security.SecurityException;
import org.opensaml.xml.security.SecurityHelper;
import org.opensaml.xml.security.keyinfo.KeyInfoGenerator;
import org.opensaml.xml.security.x509.BasicX509Credential;
import org.opensaml.xml.security.x509.X509KeyInfoGeneratorFactory;
import org.opensaml.xml.signature.KeyInfo;
import org.opensaml.xml.signature.Signature;
import org.opensaml.xml.signature.SignatureConstants;
import org.opensaml.xml.util.XMLHelper;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.w3c.dom.Element;
public class SamlClient {
private static final Logger log = LoggerFactory.getLogger(SamlClient.class);
public SamlClient() {
try {
DefaultBootstrap.bootstrap();
} catch (ConfigurationException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
private String printXml(Element element) {
String returnString = "";
TransformerFactory tfactory = TransformerFactory.newInstance();
Transformer xform;
try {
xform = tfactory.newTransformer();
Source src = new DOMSource(element);
StringWriter writer = new StringWriter();
Result out = new StreamResult(writer);
xform.transform(src, out);
returnString = writer.toString();
log.info(returnString);
try {
writer.close();
} catch (Exception e) {
e.printStackTrace();
}
} catch (TransformerConfigurationException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (TransformerException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return returnString;
}
public void attributeQuery(String username, String password, String nameId, String issuerHost) {
XMLObjectBuilderFactory builderFactory = Configuration.getBuilderFactory();
NameID nameID = (NameID) builderFactory.getBuilder(NameID.DEFAULT_ELEMENT_NAME)
.buildObject(NameID.DEFAULT_ELEMENT_NAME);
nameID.setValue(nameId);
nameID.setFormat(NameID.PERSISTENT);
Subject subject = (Subject) builderFactory.getBuilder(Subject.DEFAULT_ELEMENT_NAME)
.buildObject(Subject.DEFAULT_ELEMENT_NAME);
subject.setNameID(nameID);
Issuer issuer = (Issuer) builderFactory.getBuilder(Issuer.DEFAULT_ELEMENT_NAME)
.buildObject(Issuer.DEFAULT_ELEMENT_NAME);
issuer.setValue(issuerHost);
AttributeQuery attrQuery = (AttributeQuery) builderFactory.getBuilder(AttributeQuery.DEFAULT_ELEMENT_NAME)
.buildObject(AttributeQuery.DEFAULT_ELEMENT_NAME);
String id = getRandomId();
attrQuery.setID(id);
attrQuery.setSubject(subject);
attrQuery.setVersion(SAMLVersion.VERSION_20);
attrQuery.setIssueInstant(new DateTime());
attrQuery.setIssuer(issuer);
// AuthnRequest attrQuery = (AuthnRequest) builderFactory.getBuilder(AuthnRequest.DEFAULT_ELEMENT_NAME)
// .buildObject(AuthnRequest.DEFAULT_ELEMENT_NAME);
// attrQuery.setID(getRandomId());
// attrQuery.setVersion(SAMLVersion.VERSION_20);
// attrQuery.setIssueInstant(new DateTime());
// attrQuery.setIssuer(issuer);
// attrQuery.setForceAuthn(false);
// attrQuery.setIsPassive(false);
// attrQuery.setProtocolBinding(SAMLConstants.SAML2_PAOS_BINDING_URI);
// attrQuery.setAssertionConsumerServiceURL("https://ldf.data.kit.edu/Shibboleth.sso/SAML2/POST");
//
// NameIDPolicy idPolicy = (NameIDPolicy)builderFactory.getBuilder(NameIDPolicy.DEFAULT_ELEMENT_NAME)
// .buildObject(NameIDPolicy.DEFAULT_ELEMENT_NAME);
// idPolicy.setAllowCreate(true);
// attrQuery.setNameIDPolicy(idPolicy);
MarshallerFactory marshallerFactory = Configuration.getMarshallerFactory();
Marshaller marshaller = marshallerFactory.getMarshaller(attrQuery);
Element element;
try {
element = marshaller.marshall(attrQuery);
log.debug(XMLHelper.prettyPrintXML(element));
} catch (MarshallingException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
Envelope envelope = (Envelope) builderFactory.getBuilder(Envelope.DEFAULT_ELEMENT_NAME)
.buildObject(Envelope.DEFAULT_ELEMENT_NAME);
Body body = (Body) builderFactory.getBuilder(Body.DEFAULT_ELEMENT_NAME).buildObject(Body.DEFAULT_ELEMENT_NAME);
body.getUnknownXMLObjects().add(attrQuery);
envelope.setBody(body);
BasicSOAPMessageContext soapMessageContext = new BasicSOAPMessageContext();
soapMessageContext.setOutboundMessage(envelope);
BasicX509Credential signingCredential;
X509Certificate cert = getCertificate();
PrivateKey privKey = getPrivateKey();
if (cert == null || privKey == null)
return;
signingCredential = SecurityHelper.getSimpleCredential(cert, privKey);
HttpClientBuilder clientBuilder = new HttpClientBuilder();
Signature signature = (Signature) builderFactory.getBuilder(Signature.DEFAULT_ELEMENT_NAME)
.buildObject(Signature.DEFAULT_ELEMENT_NAME);
X509KeyInfoGeneratorFactory keyInfofc = (X509KeyInfoGeneratorFactory) Configuration
.getGlobalSecurityConfiguration().getKeyInfoGeneratorManager().getDefaultManager()
.getFactory(signingCredential);
keyInfofc.setEmitEntityCertificate(false);
keyInfofc.setEmitEntityCertificateChain(false);
KeyInfoGenerator keyInfogen = keyInfofc.newInstance();
try {
KeyInfo keyInfo = keyInfogen.generate(signingCredential);
signature.setSigningCredential(signingCredential);
signature.setSignatureAlgorithm(SignatureConstants.ALGO_ID_SIGNATURE_RSA_SHA1);
signature.setCanonicalizationAlgorithm(SignatureConstants.TRANSFORM_C14N_EXCL_WITH_COMMENTS);
signature.setKeyInfo(keyInfo);
attrQuery.setSignature(signature);
Map<String, Boolean> newFeatures = new HashMap<String, Boolean>();
newFeatures.put("http://apache.org/xml/features/disallow-doctype-decl", false);
BasicParserPool pool = new BasicParserPool();
pool.setNamespaceAware(true);
pool.setBuilderFeatures(newFeatures);
org.apache.commons.httpclient.HttpClient httpClient = clientBuilder.buildClient();
httpClient.getParams().setAuthenticationPreemptive(true);
httpClient.getState().setCredentials(new AuthScope("idp.scc.kit.edu", 443, AuthScope.ANY_REALM),
new UsernamePasswordCredentials(username, password));
// httpClient.getState().addCookie(new Cookie("idp.scc.kit.edu", "JSESSIONID", getRandomId().substring(1), "/idp/profile/SAML2/SOAP/ECP", 3600, true));
HttpSignableSoapClient client = new HttpSignableSoapClient(httpClient, pool, signature);
// HttpSOAPClient client = new HttpSOAPClient(httpClient, pool);
client.send("https://idp.scc.kit.edu/idp/profile/SAML2/SOAP/ECP", soapMessageContext);
Envelope response = (Envelope) soapMessageContext.getInboundMessage();
Body responseBody = response.getBody();
List<XMLObject> xmlObjects = responseBody.getUnknownXMLObjects();
Response re = (Response) xmlObjects.get(0);
element = marshaller.marshall(re);
log.info(XMLHelper.prettyPrintXML(element));
} catch (SecurityException e) {
e.printStackTrace();
} catch (SOAPException e) {
e.printStackTrace();
} catch (MarshallingException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
private String getRandomId() {
String randomId = "";
try {
SecureRandomIdentifierGenerator randomGen = new SecureRandomIdentifierGenerator();
randomId = randomGen.generateIdentifier();
} catch (NoSuchAlgorithmException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return randomId;
}
private PrivateKey getPrivateKey() {
RandomAccessFile raf = null;
PrivateKey privKey = null;
try {
raf = new RandomAccessFile("client.pk8", "r");
byte[] buf = new byte[(int) raf.length()];
raf.readFully(buf);
PKCS8EncodedKeySpec kspec = new PKCS8EncodedKeySpec(buf);
KeyFactory kf = KeyFactory.getInstance("RSA");
privKey = kf.generatePrivate(kspec);
} catch (IOException e) {
e.printStackTrace();
} catch (NoSuchAlgorithmException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (InvalidKeySpecException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} finally {
if (raf != null) {
try {
raf.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
return privKey;
}
private X509Certificate getCertificate() {
InputStream in = null;
X509Certificate cert = null;
try {
in = new FileInputStream("client.crt");
CertificateFactory cf = CertificateFactory.getInstance("X.509");
cert = (X509Certificate) cf.generateCertificate(in);
} catch (IOException e) {
e.printStackTrace();
} catch (CertificateException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} finally {
if (in != null) {
try {
in.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
return cert;
}
}
# Root logger option # Root logger option
log4j.rootLogger=INFO, stdout log4j.rootLogger=DEBUG, stdout
log4j.logger.edu.kit.scc=DEBUG log4j.logger.edu.kit.scc=DEBUG
# Redirect log messages to console # Redirect log messages to console
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment