Wednesday, June 12, 2013

Genereate .p7b file from multiple .cer files

A p7b file can contain many CA certificates. This can for example be the case when creating a bundle of CA certificates. As was the case for me.

In a project I'm working on we want to bundle all the trused CA certificates in one file. The file for this purpose was p7b.

We used openssl to do it.

The first thing that needs to be done is to convert the .cer files to PEM.

openssl x509 -in myCA1.cer -inform DER -outform pem -out myCA1.pem
openssl x509 -in myCA2.cer -inform DER -outform pem -out myCA2.pem

And then we bundle the PEM files

openssl crl2pkcs7 -nocrl -certfile myCA1.pem -certfile myCA1.pem -outform PEM -out bundle.p7b

To add another PEM fil just add another -certfile argument.

Monday, November 12, 2012

Verifying signatures with OpenSAML

As the post about signing discussed, it is very important that sign and verify messages when federating with SAML.

When verifying a signature of a message it is recommended to first validate the message with a SAML profile validator to ensure that the signature follows SAML standard. Afterwords the cryptography validation of the signature can be done by a SignatureValidator.

PS. This validation only performs a cryptographic validation of the signature. It does not check the certificate used for signing against any trusted CA.

To confirm the validity of the certificate a trust engine must be used in the validation.

Here is a full example of the crytographic validation.

SAMLSignatureProfileValidator profileValidator = new SAMLSignatureProfileValidator();

profileValidator.validate(entityDescriptor.getSignature());

SignatureValidator sigValidator = new SignatureValidator(cred);

sigValidator.validate(entityDescriptor.getSignature());
SignatureValidator is instansiated with the credenial is basically the public key for the private key for which the message should have been signed with.
This could have been extracted from metadata or it could have been sent in the SAML message. If the public key was sent in the message, it is very important to validate the key against a CA.

Signing with OpenSAML

When exchanging information with SAML it is highly recomended to sign and verify signatures on all messages. This to ensure the the sender really is how he seas he is and that the information sent has not been manipulated during transport.

Every SAML object that implements the SignableXMLObject interface can be signed.

The signing of a SAML message is done in three steps. First all the properties for the signature is put in a Signature object. Properties that can be set include singing credentials, algorithm and optionally a key info object that can bu used during verification.
signature.setSigningCredential(credential);
signature.setSignatureAlgorithm(SignatureConstants.ALGO_ID_SIGNATURE_RSA_SHA1);
signature.setCanonicalizationAlgorithm(SignatureConstants.ALGO_ID_C14N_EXCL_OMIT_COMMENTS);
The Signature object is then added to the SAML object using the setSignature method.
entityDescriptor.setSignature(signature); The second step is to marchal the object. This must be done before signing or else you will get a message like this.

SEVERE: Unable to compute signature, Signature XMLObject does not have the XMLSignature created during marshalling.


Element element = Configuration.getMarshallerFactory().getMarshaller(entityDescriptor).marshall(entityDescriptor);
The third step is to perform the actual signing to produce a cryptographic signature, this is done with the Signer class.
Signer.signObject(signature);
Here is how the signed object might look after signing and marshalling.












a3HbFE7e2n/x2yqDTKyXrQNaDHs=


b8cPqphGwZIvBy1DuEWoS/lhreiMp7WtcukC2TkXl2nRwuJ5i1TN+ifefxvsjs9ocQ4XAL6EVrXXaJvyRMkepuDYAFqYYGle4iPkl5XZpCDeMjTEt/T45f3etOdn5EGmNgA5MwUQxFTnERYkdNiN//r8BYuNfEKFNd+BqyVRjRWBbgywWRfSBBz8u1m4aysyeYcz9M72pI9YhC4QqRtXG7cght78Lt3JLUMDHKZMg9itvs1rPwItLFCzaJr57Q/V+nQ8uIb0bCUUrXZw9hGl5b3SYIuJLdHI0IDPt8YGpNa/yzVqnKOk5FvhASmMQur3/CbdCvRKr8yTpalW3zDgfw==


Wednesday, November 7, 2012

OpenSAML sample code

One of my visitor found this public source code. The project a Danish project that implements a service provider using OpenSAML.

 https://view.softwareborsen.dk/Softwareborsen/oiosaml.java/sp/trunk/src/dk/itst/oiosaml/sp/service/

Thanks to Rholdan Ortiz!


There is also the Norwegian electronic voting system. This also implements a service provider.

https://source.evalg.stat.no/svn/eVote-ergo/admin-frontend/src/main/java/no/evote/service/security/saml/

Wednesday, June 20, 2012

Syncing Active Directory with OpenAM datastore using LSC

Lately I have been tasked to set up an OpenAM server that should authenticate user against an existing AD server.


I have found three usual approaches to this problem.

  • Use the AD as a OpenAM user store 
  • The AD authentication module can be used to authenticate user against AD. 
  • Use some kind tool could be used to synchronize AD and OpenAM user store.

The problem with the first one is that it require some changes to the AD which I am not allowed to implement.


The second one works fine if all you want to do is authenticate the user, as far as I've seen there aren’t any good ways to get more information about the user for example email address and phone number. The module can be configured to populate the default user store in OpenAM with user attributes from AD, but this will only happen on the first login. If the user changes email or phone number in the future the changes won't be reflected in OpenAM.


I ended up using both AD authentication module and synchronization. The authentication module for authentication directly against AD and synchronization for getting the attributes. For synchronization I used LSC.


In the next section I will describe the LSC configuration. This is not a beginners guide to LCS so if you are new to it, I recommend you checking out some of the tutorials here http://lsc-project.org/wiki/documentation/2.0/start


LSC configuration
In my OpenAM configuration different groups have different authorization so I want to sync both users and groups. 


This is accomplished by defining two tasks.


lsc.tasks = ADuser, ADgroup

Syncing users
First the properties for the srcService

lsc.tasks.ADuser.srcService = org.lsc.jndi.SimpleJndiSrcService

lsc.tasks.ADuser.srcService.baseDn = cn=Users

# Filter to list all entries to synchronize
lsc.tasks.ADuser.srcService.filterAll = (&(sAMAccountName=*)(objectClass=user)(memberOf=CN=OpenAMUsers,CN=Users,DC=capra,DC=no))

# Attributes to read from all entries used to match objects between source and destination
lsc.tasks.ADuser.srcService.pivotAttrs = sAMAccountName

# Filter to read one entry to synchronize, based on pivotAttrs above
# This filter may contain one or several pivotAttrs defined above, like "{attributeName}"
lsc.tasks.ADuser.srcService.filterId = (&(objectClass=user)(|(sAMAccountName={sAMAccountName})(sAMAccountName={uid})))

# Attributes to read from each entry used to read and write data
lsc.tasks.ADuser.srcService.attrs = mail cn sAMAccountName sn givenName

Short description. The filterAll attribute is used to pick out all users of interest. In this case I'm specifying objectType users and they should have an sAMAccountName. I have also placed all the users to be synced in a group called OpenAMUsers as the users to be synced is only a subset of the user base. 


The name to look at when matching users is the sAMAccountName and is specified in pivotAttrs. The filterId is a bit tricky In order to understand how to define this, I recommend reading  http://lsc-project.org/user-guide/#matching-up-entries. The attr is the attributes I would like to read from the source.

The dstService
lsc.tasks.ADuser.dstService = org.lsc.jndi.SimpleJndiDstService
lsc.tasks.ADuser.dstService.baseDn = ou=People

# Filter to list all entries to synchronize
lsc.tasks.ADuser.dstService.filterAll = (&(uid=*)(objectClass=inetOrgPerson))

# Attributes to read from all entries used to match objects between source and destination
lsc.tasks.ADuser.dstService.pivotAttrs = uid 

# Filter to read one entry to synchronize, based on pivotAttrs above
# This filter may contain one or several pivotAttrs defined above, like "{attributeName}"
lsc.tasks.ADuser.dstService.filterId = (&(objectClass=inetOrgPerson)(|(uid={sAMAccountName})(uid={uid})))

# Attributes to read from each entry used to read and write data
lsc.tasks.ADuser.dstService.attrs = mail cn uid objectClass sn givenName inetUserStatus

On the destination(OpenAM) all users lies under ou=People so base dn is ou=People.
FilterId sepecifies user of interest in the destination. The attrs in this case is the attributes I would like to update.


lsc.tasks.ADuser.dn = "uid=" + srcBean.getAttributeValueById("sAMAccountName") + ",ou=People"

In OpenAM the users are by default identified with the uid attribute. I thought it wise to keep this so the DN is concatenated with the account name and the user base dn.

Sync options specify how to update the info in destination.


# syncoption for the uid attribute: At creation the uid is set to sAMAccountName from src
lsc.syncoptions.ADuser.uid.action = K
lsc.syncoptions.ADuser.uid.objectClass.create_value = srcBean.getAttributeValueById("sAMAccountName")

#Insert objectClass
lsc.syncoptions.ADuser.objectClass.action = K
lsc.syncoptions.ADuser.objectClass.create_value = "iplanet-am-auth-configuration-service";"sunIdentityServerLibertyPPService";"sunAMAuthAccountLockout";"sunFederationManagerDataStore";"iplanet-am-managed-person";"iPlanetPreferences";"sunFMSAML2NameIdentifier";"person";"inetorgperson";"organizationalperson";"inetuser";"iplanet-am-user-service";"top"

#Set defualt sn
lsc.syncoptions.ADuser.sn.action = F
lsc.syncoptions.ADuser.sn.default_value = "noSN"

#Setting active user
lsc.syncoptions.ADuser.inetUserStatus.action = K
lsc.syncoptions.ADuser.inetUserStatus.default_value = "Active"

Pretty much straight forward, the uid is set to sAMAccountName, this is set to only update at creation time. This is the attribute to match users and it is not changed. 


The objectClass is updated at creation time with the classes users use in OpenAM. This is needed for OpenAM to recognize the users. 


For some reason the OpenAM data store schema demands SN to be set, so if it is not set in AD it is set to noSN. 


User status is set to Active. 


All attributes specified in the attrs settings with the same name in source and destination is automatically updated if nothing else is configured in sync options. In this case givenName, mail, cn.


Syncing groups
# Base DN for searches in the directory
lsc.tasks.ADgroup.srcService.baseDn = cn=Users

# Filter to list all entries to synchronize
lsc.tasks.ADgroup.srcService.filterAll = (&(cn=*)(objectClass=group)(memberOf=CN=OpenAMGroups,CN=Users,DC=capra,DC=no))

# Attributes to read from all entries used to match objects between source and destination
lsc.tasks.ADgroup.srcService.pivotAttrs = cn

# Filter to read one entry to synchronize, based on pivotAttrs above
# This filter may contain one or several pivotAttrs defined above, like "{attributeName}"
lsc.tasks.ADgroup.srcService.filterId = (&(objectClass=group)(cn={cn}))

# Attributes to read from each entry used to read and write data
lsc.tasks.ADgroup.srcService.attrs = cn member

As with the users, to make it easier to find the groups I want to sync, I have added the groups to a group, OpenAMGroups. As you can see in the filterAll property, only the groups in OpenAMGroups are synced.

The expression in the filterId becomes a lot easier to understand if the identifying attributes have the same name at source and destination. Again have a look at http://lsc-project.org/user-guide/#matching-up-entries for more information on filterId.


# Base DN for searches in the directory
lsc.tasks.ADgroup.dstService.baseDn = ou=groups

# Filter to list all entries to synchronize
lsc.tasks.ADgroup.dstService.filterAll = (cn=*)

# Attributes to read from all entries used to match objects between source and destination
lsc.tasks.ADgroup.dstService.pivotAttrs = cn

# Filter to read one entry to synchronize, based on pivotAttrs above
# This filter may contain one or several pivotAttrs defined above, like "{attributeName}"
lsc.tasks.ADgroup.dstService.filterId = (cn={cn})

# Attributes to read from each entry used to read and write data
lsc.tasks.ADgroup.dstService.attrs = cn uniqueMember objectClass

The attributes cn, uniqueMember and objectClass. UniqueMember is OpenAMs attribute for members and the object class needs to be set in order for the groups to be recognized by OpenAM.

lsc.tasks.ADgroup.dn = "cn=" + srcBean.getAttributeValueById("cn") + ",ou=groups"

New DN is concatenated.

# Set default delimiter for multiple values for an attribute.
# This is normally a semi-colon (;) but can be problematic when writing complex JavaScript
lsc.syncoptions.ADgroup.default.delimiter = $

The delimiter is set to be $ as semicolon is used in the more complex javascript expression below.

#Insert objectClass
lsc.syncoptions.ADgroup.objectClass.action = K
lsc.syncoptions.ADgroup.objectClass.create_value = "groupofuniquenames";"top"

Object class is set to standard values.

#members syncing
lsc.syncoptions.ADgroup.uniqueMember.action = F
lsc.syncoptions.ADgroup.uniqueMember.force_value = var uniqueMember = new Array();\
var members = srcBean.getAttributeValuesById("member").toArray();\
for (var i = 0; i < members.length; i++) {\
        var member = members[i];\
        member.replace(",CN=Users,DC=capra,DC=no", ",ou=people,dc=opensso,dc=java,dc=net").replace("CN", "uid");\
        uniqueMember.push(member);\
}\
members

Here is the best part, it shows some of the power in LSC.
What we need to do here is to take all the member attribute entries and change the dn before syncing.  


Every property value can be a javascript expression so we simply get the attributes, run them through a loop, do some string manipulation and return the new list.

This is the configuration I used. It works fine on OpenAM 10.0.0 and Windows Server 2008 R2.

If there are any questions or problems, feel free to post a comment.

Friday, May 11, 2012

SAML Web Profile


What is it?
SAML Web Profile is a subset of the SAML specification. It specifies the authentication process of a user using a web browser.

How does it work?
In this post I will show a usual case using the web profile with HTTP redirect. The flow in the authentication process is illustrated in the figure below.




The authentication process could be said to involve five steps

1. User tries to get access
The process begins with a not authenticated user trying to get access to a protected part of the application (SP). Some form of filter is put in place to catch the user.

2. The user is redirected to the Identity provider(IDP)
When the filter detects a user who is not authenticated, the user is sent to the IDP using HTTP redirect.

3. The user is authenticated
This step does not involve any interaction with the SP. The IDP has full responsibility for authenticating the user in a secure way.

4. Authenticated user is sent back to the SP
When the authentication is successfully completed the user is sent back to the SP together with a SAML artifact. The artifact is more or less a pointer to the user information at the IDP. This information could contain sensitive user information and is therefore not sent via the browser.

5. Request user information
When the SP receives the artifact it is sent to a web service at the IDP. The web service returns the  user information in a SAML Artifact Response. One of the things returned in the response is a pseudonym. The pseudonym is an identifier that is unique for that user. If the pseudonym is specified as persistent the pseudonym is always the same, if it is transient it is regenerated at every login.

Usually the IPD also returns a security level, specifying how safe the authentication was. This can later be used by the SP to regulate what is showed the the user.

This is how the federeation with SAML web profile works on a low level. This can be good to know when working with identity federation and especially when debugging.

Usually when you set up a identity federation this is done with some of the many tools available.
These tools helps with the low lever communication.

Tools
Here is a subset of the tools available

OpenAM former OpenSSO is an open source system access control and authentication and supports SAML.

OpenSAML is an open source framework that helps in using SAML on a low level.

OIF is Oracles solution for identity federation.

Friday, March 9, 2012

Monitoring heap space on local JMVs in Java 5

In the last couple of days I have been helping a colleague with a problem. The problem is that they have a couple  of java processes running on a server. These processes go out of memory every no and then and it is important that they can get a notice when this is about to happen.

First I had a look at some monitoring applications.

  • jConsole - Had no email functions. It looks like you could install a MBean with mail funtions but I think that has to be done from inside each process and I'm not allowed to change the code.
  • Nagios - Is a big infrastructure monitoring utility which have a JMX pluging, but it seemed to overkill.
  • Munin - Appears to have some notification ability, but seems hard to set up. 

The solution was to write my own little notification and monitoring program. Often not the best solution but I also saw some value in learning more about JMX monitoring.

I think everybody can agree, it better to fix the memory problem then to just restart the servers when they are running out of memory, but no time for that right now.

Enough of problem, now to the solution =)

To get the memory used by the processes, I needed to summarize the memory used y each process.
As I were going to monitor all the JVMs running om the machine I have to somehow connect to the JMX of every process.

I first stumbled on to the Attach API in java 6 which have a lot of functionality for listing and working with the VMs on the machine. Problem is I was going to build the program for java 5. So I soon dropped this.

Second I tried to find out how jConsole lists the VMs in its startup dialog. Finally I found the class  sun.jvmstat.monitor.MonitoredHost used by the jvmstat program. As Oracle states it's not recommended to use sun.* classes because they are not guaranteed to work in future releases and all platforms.   http://www.oracle.com/technetwork/java/faq-sun-packages-142232.html. But because this is a simple utility meant for use on one server I decided to use them anyway.

So I could use the method activeVms to get a list of all process ID of the active vms.

MonitoredHost.getMonitoredHost("localhost").activeVms();

But how to connect to the JMX of a process only using a PID. Google gave me very many unhelpful suggestions about the Attach API. But finally I found another helpful class in the sun.* classes. sun.management.ConnectorAddressLink

Using the method importFrom I got the JMX address for the JVM process and the hard part was over.

ConnectorAddressLink.importFrom(pid);

Then it was just the simple task of getting the max and used heapspace from the Memory MX Bean.

jmxConnector = JMXConnectorFactory.connect(serviceUrl, null);
  MBeanServerConnection con = jmxConnector.getMBeanServerConnection();
  MemoryMXBean memBean = ManagementFactory.newPlatformMXBeanProxy(con, ManagementFactory.MEMORY_MXBEAN_NAME, MemoryMXBean.class);
memBean.getHeapMemoryUsage().getUsed();
memBean.getHeapMemoryUsage().getMax();

So to the whole process for calculating used heap space on the machine would look something like this

long usedHeapSpace = 0;
for (Object OPid : MonitoredHost.getMonitoredHost("localhost").activeVms()) {
 int dpid = Integer.parseInt(OPid.toString());
 String address = ConnectorAddressLink.importFrom(dpid);
 JMXServiceURL serviceUrl = new JMXServiceURL(address);
 JMXConnector jmxConnector = JMXConnectorFactory.connect(serviceUrl, null);
 MBeanServerConnection con = jmxConnector.getMBeanServerConnection();
 MemoryMXBean memBean = ManagementFactory.newPlatformMXBeanProxy(con
   , ManagementFactory.MEMORY_MXBEAN_NAME
   , MemoryMXBean.class);

 usedHeapSpace += memBean.getHeapMemoryUsage().getUsed();
 jmxConnector.close();
}

Note that all java processes must use the -Dcom.sun.management.jmxremote for the JMX to be enabled.
If there are processes without this flag the resulting calculation will be incorrect.

So to summarize, bad lessons learned, there is a lot of fun stuff in sun.* classes =)