Author Archives: yogesh.mali@gmail.com

Use of clockskew in SAML Assertion in SAML Protocol

In this post, I will explain how we can use clockskew in SAML Assertion to avoid a general problem when a Service Provider (SP) receives a SAML response from Identity Provider (IdP) and if both of them are on different machines which is generally the scenario.

So when a user accesses a SP application, SP sends an authentication request to IdP and IdP sends a SAML response to SP. The typical SAML response looks like below:

<saml2p:Response Destination="https://localhost:8443/spring-security-saml2-sample/saml/SSO"
                 ID="_8ced26c57648ea420c5e27ac7f3d78b3"
                 InResponseTo="a3ei0bej41ie0dg738jji60271f1bca"
                 IssueInstant="2018-10-31T18:39:05.109Z"
                 Version="2.0"
                 xmlns:saml2p="urn:oasis:names:tc:SAML:2.0:protocol"
                 xmlns:xsd="http://www.w3.org/2001/XMLSchema"
                 >
    <saml2:Issuer xmlns:saml2="urn:oasis:names:tc:SAML:2.0:assertion">https://sts.betterjavacode.com/sts</saml2:Issuer>
    <ds:Signature xmlns:ds="http://www.w3.org/2000/09/xmldsig#">
        <ds:SignedInfo>
            <ds:CanonicalizationMethod Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#" />
            <ds:SignatureMethod Algorithm="http://www.w3.org/2000/09/xmldsig#rsa-sha1" />
            <ds:Reference URI="#_8ced26c57648ea420c5e27ac7f3d78b3">
                <ds:Transforms>
                    <ds:Transform Algorithm="http://www.w3.org/2000/09/xmldsig#enveloped-signature" />
                    <ds:Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#">
                        <ec:InclusiveNamespaces PrefixList="xsd"
                                                xmlns:ec="http://www.w3.org/2001/10/xml-exc-c14n#"
                                                />
                    </ds:Transform>
                </ds:Transforms>
                <ds:DigestMethod Algorithm="http://www.w3.org/2001/04/xmlenc#sha256" />
                <ds:DigestValue>k6k9seVwZT8qEfainB+HDUJmv7wLwPjJxRARgrFLk3E=</ds:DigestValue>
            </ds:Reference>
        </ds:SignedInfo>
        <ds:SignatureValue>
eYl7/5Bg4f2ZtXYl1Tp/ZW4CIqna1sjHjVSB/zhj3NHncQu7pq9PBTdWz0JEaE8+efICz7trDQvI
J0tih35Vg7NqDtOeps7vMttV0XvrnWKIXEqrscyNgkhwy+KW2oprKIWTJq6y3Z0kQ7n2DlTRkfAE
yLRPxqr8AZU+77Tbv4DmTQVp934ivibUaMNU79nkhMMo7vf0ldpeNCe5Ll5Q7nxgNBCrL4mhbGdU
DNJDVqJIhQZDJUYhBVZSgLo6mYLxf0ndQr5+GdcvO3i8VlooH49I5ZO6LfsBlNiSU6WezC0Fcz8J
biodrT3h62Jny8FKUgYfXA8i0ZoAerCxHmLGFQ==
</ds:SignatureValue>
        <ds:KeyInfo>
            <ds:X509Data>
                <ds:X509Certificate>MIICpTCCAY2gAwIBAgIHAKQk/Tty7TANBgkqhkiG9w0BAQsFADATMREwDwYDVQQDDAhJbmZvclNU
UzAeFw0xNzExMTAxNjIwMjVaFw0xOTExMTAxNjIwMjZaMBMxETAPBgNVBAMMCEluZm9yU1RTMIIB
IjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAuy40GofgfSldiu7AXRSWQZo8YIUmdJOXV5gd
YUiIBggcm5J+jttd21av9AWBDLtvekIqgG+nM1SEarDNlCgrnThqDtdsBDnT+B5FQowLwqNQZb0C
6PSWccp484OLHhv3YwbjV/IxgW6wlv2EejPF93NTPc5TkkpIKIEARJwKiUvuwzkcX1atD8HESj8/
5wZhK3g3MSv+CaJb1Y732U2aa34RI6HYRNlKRsqRj55SZnPs3AmIBL/rdVbt5eYJdK+jXSOMQ9Sb
TNkgTAYKnlSQP8NhsNc1Y5ZJ231KD3rSqHEXwpKVXFuEgtBnCL9utqyUU0Fu9PNJJj0hf9otMJw2
pQIDAQABMA0GCSqGSIb3DQEBCwUAA4IBAQAsqxA/+llqNtJq/VPtAa0XwtldB7/4Gew5LgfU5Yj7
/ruHuxCh03xfnLyjo0bxrFeMbhHMg4MzJhgah0zTIl4WMRI781CiMxGfMdvQAHhY5hgpryqKUTbH
qcIoW1WkTEL+TrOSk2gjL/n/4KsUJ3XKeI4j4h2RDvbIF8u9cbrB5RupEwJlo/pK3mCr3GQGFxVX
4yli+AysMmz8JWz2hWQad0QQr9KIYmZdgauNt7uYn4u+7cngtTtQF/EMoZU1pAFI5lDP13mxI1rR
eYGzoKhGfHIy7TiXYvqX0vFomzkgr6D0DnRlRkQR8J5EVtnGZ7sF50KlNviG+IxrPNndUdeX</ds:X509Certificate>
            </ds:X509Data>
        </ds:KeyInfo>
    </ds:Signature>
    <saml2p:Status>
        <saml2p:StatusCode Value="urn:oasis:names:tc:SAML:2.0:status:Success" />
    </saml2p:Status>
    <saml2:Assertion ID="_43514fee402111bfa8ef07e2bb3e1816"
                     IssueInstant="2018-10-31T18:39:05.109Z"
                     Version="2.0"
                     xmlns:saml2="urn:oasis:names:tc:SAML:2.0:assertion"
                     >
        <saml2:Issuer>https://sts.betterjavacode.com/sts</saml2:Issuer>
        <saml2:Subject>
            <saml2:NameID Format="urn:oasis:names:tc:SAML:2.0:nameid-format:transient"
                          NameQualifier="https://sts.betterjavacode.com/sts"
                          SPNameQualifier="https://localhost:8443/spring-security-saml2-sample/saml/metadata"
                          >-74375301938178262591541011144180</saml2:NameID>
            <saml2:SubjectConfirmation Method="urn:oasis:names:tc:SAML:2.0:cm:bearer">
                <saml2:SubjectConfirmationData InResponseTo="a3ei0bej41ie0dg738jji60271f1bca"
                                               NotOnOrAfter="2018-10-31T18:44:05.109Z"
                                               Recipient="https://localhost:8443/spring-security-saml2-sample/saml/SSO"
                                               />
            </saml2:SubjectConfirmation>
        </saml2:Subject>
        <saml2:Conditions NotBefore="2018-10-31T18:39:05.109Z"
                          NotOnOrAfter="2018-10-31T18:44:04.109Z"
                          >
            <saml2:AudienceRestriction>
                <saml2:Audience>https://localhost:8443/spring-security-saml2-sample/saml/metadata</saml2:Audience>
            </saml2:AudienceRestriction>
        </saml2:Conditions>
        <saml2:AttributeStatement>
            <saml2:Attribute Name="http://schemas.microsoft.com/claims/Tenant">
                <saml2:AttributeValue xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
                                      xsi:type="xsd:string"
                                      >ABC Company</saml2:AttributeValue>
            </saml2:Attribute>
            <saml2:Attribute Name="http://schemas.microsoft.com/claims/Identity">
                <saml2:AttributeValue xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
                                      xsi:type="xsd:string"
                                      >testuser</saml2:AttributeValue>
            </saml2:Attribute>
            <saml2:Attribute Name="http://schemas.xmlsoap.org/claims/CommonName">
                <saml2:AttributeValue xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
                                      xsi:type="xsd:string"
                                      >Test User</saml2:AttributeValue>
            </saml2:Attribute>

            <saml2:Attribute Name="http://schemas.microsoft.com/claims/Email">
                <saml2:AttributeValue xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
                                      xsi:type="xsd:string"
                                      >test.user@betterjavacode.com</saml2:AttributeValue>
            </saml2:Attribute>
            <saml2:Attribute Name="http://schemas.microsoft.com/claims/Session">
                <saml2:AttributeValue xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
                                      xsi:type="xsd:string"
                                      >-65311121040491585821541011144177</saml2:AttributeValue>
            </saml2:Attribute>                        
        </saml2:AttributeStatement>
        <saml2:AuthnStatement AuthnInstant="2018-10-31T18:39:05.109Z"
                              SessionIndex="31079178551135950171541011144177"
                              >
            <saml2:AuthnContext>
                <saml2:AuthnContextClassRef>urn:oasis:names:tc:SAML:2.0:ac:classes:PasswordProtectedTransport</saml2:AuthnContextClassRef>
            </saml2:AuthnContext>
        </saml2:AuthnStatement>
    </saml2:Assertion>
</saml2p:Response>

Now SP and IdP are on different machine. And there can be a case that their clocks are not synced. So when IdP generates the response, it has an element SubjectConfirmationData that contains NotBefore and NotOnOrAfter. Subject indicates details about the user and relying party who is receiving the assertion. Relying party has to verify that the assertion is coming from the right issuer.

NotBefore – Time before which subject can not be validated.

NotOnOrAfter – Time on or after which subject has expired.

Similarly, there will be Conditions element in the assertion and this element will also contain attributes NotBefore or NotOnOrAfter. These two attributes indicate at what time assertion will be valid and after what time, it will be expired.

Problem

Now if we take into account a scenario where system clocks of IdP and SP are not in sync and if Idp clock is ahead of Sp clock, how do we handle this scenario?

Solution

So as described in above scenario, then assertion validation will fail because of NotBefore time will be greater than the time on SP machine.

To solve this issue, we can either make sure IdP and SP clocks are in sync. But this seems human-dependent solution and getting clocks in sync is not always practical solution.

Another way this can be solved by adding a clockskew in SAML assertion. A relying party that is consuming the assertion should apply small clockskew to time to accommodate small changes in time.

private int clockSkew = 120;

SubconfirmationData subjectConfirmationData = subjectConfirmation.getSubjectConfirmationData();

if(subjectConfirmationData.getNotOnOrAfter().plusSeconds(clockSkew).isBeforeNow())
{
 // throw error - Subject Confirmation Data has expired
}

/***
*
*
*/

if (conditions.getNotBefore() != null && conditions.getNotBefore().minusSeconds(clockSkew).isAfterNow()) 
{
      throw new SAMLException("Assertion condition notBefore is not valid");
}

if (conditions.getNotOnOrAfter() != null && conditions.getNotOnOrAfter().plusSeconds(clockSkew).isBeforeNow()) 
{
      throw new SAMLException("Assertion condition notOnOrAfter is not valid");
}

 

References

  1. SAML Specification
  2. SAML assertion with NotBefore and NotOnOrAfter

Building user interface for Social KPI

As part of building the web application Social KPI SocialPie, we will be building the backend and frontend in module forms. Eventually, the plan is to deploy the application on the cloud. But backend and frontend are not different services as Microservice architecture generally dictates. In this post, I will show how we will be building a user interface for Social KPI using thymeleaf and angular JS.

The idea is to create a skeleton of UI by bringing different points in the discussion to make our decisions about choosing different parts of UI. In the previous post here, we discussed user flow.

User Story for user interface

  1. A user will access the application and will see the initial screen for login or sign up.
  2. If the user has not signed up before, he will sign up with the first name, last name, email, company name, password.
  3. Once the user signs up, the user will receive a confirmation email to sign in. This user will be the administrator to manage its company.
  4. A user can come back to the login screen through confirmation email. Then the user will enter credentials.
  5. User will see the company profile. User will have the option to modify company profile details as well as to add users with role REPORT.
  6. Administrator when adding these users will submit their first name, last name, email, and role as REPORT. Administrator will have an option to send emails to these users through portal or provide them username and password.
  7. Once the users with role REPORT login, they will have the option to change their temporary password. Once the password has been changed, he will be redirected to the reports screen.
  8. Administrator can also access reports screen any time.
  9. On Reports screen, user will have an option to synchronize the data with social media APIs to get the latest data. This will be once in a day option considering the limitation on access of APIs.
  10. On Reports screen, user will have an option to generate the report post-synchronization. User will be able to see Jasper reports in graph as well in data form. User will have an option to send these reports to other people in email.
  11. There will be logout and home screen options on the screen all the time.
  12. Home for user with Report role will be their profile information.

The skeleton of the user interface

Screen 1:

First Page

Screen 2:

Second Page

Screen 3:

Third Page

Screen 4:

Forth Page

Screen 5:

Fifth Page

Screen 6:

Sixth Page

Screen 7:

Seventh Page

Conclusion

In this post, we showed the skeleton of the user interface for the Social KPI web application. Of course, this is not a final design, but as we go on building it, we will have our changes and I will also show the code for this design. In future posts, I will be showing the functioning UI for login and sign-up pages.

 

 

 

Difference between java.home and JAVA_HOME

When setting up environments, one of the few things we have to do is set up environment variables. JAVA_HOME is the most common environment variable you have to set up, especially if doing Java development. So previously, I had asked this question about knowing the difference between java.home and JAVA_HOME on StackOverflow here.

Question

Basically, I was using System.getProperty("java.home") in my code and it would return difference value from what I had set for JAVA_HOME. I was wondering why the difference. This post is about the explanation of the difference between these two properties.

Answer

There are some contradictory answers about the difference. But what I found on my own is that java.home is a system variable created based on Java Runtime Environment (JRE). This is more like a system variable. JAVA_HOME is an environment variable, this is required when you install JDK. Java Development Kit(JDK) is an environment based software that an individual installs and this software needs Java Runtime Environment (JRE).  So JDK is a superset of JRE.

On any system, when you ask for JAVA_HOME environment variable, you generally get the path of your JDK installation. But since java.home is a system variable, the only way to find out that variable is through system properties. Also some machines have default Oracle installed JRE path and java.home might point to that path. You won’t be able to do any Java-based development if you do not have JAVA_HOME defined.

But the interesting fact is when you install JDK, it also installs JRE. But when you verify java.home , it doesn’t point to the same root path where JDK has been installed. One main reason for this, is that despite when you install JDK, JRE and JDK are two different products and many machines have default JRE installed.

Conclusion

In this post, I showed the difference between JAVA_HOME and java.home. Subscribe to my blog here.

References

  1. System Properties – Oracle Documentation

 

 

 

All about the skill of programming

Yes, this will be the post where we dissect the skill of programming. Recently I came across a lot of beginner’s questions from friends and families who want to get into programming. But also if I want to go back in time and want to give advice to 10 years younger me, what advice would I give? How would I approach programming skills differently compared to what I did?

Before I move forward, if you want to read design patterns, you can visit that link.

Why does programming matter?

Most of us are not born programmers or smart enough to gauge our ability to sit in front of a computer for hours and write something in a completely foreign language to mankind. Programming is definitely not foreign anymore, but there are still a lot of people in the world, who don’t know anything about how computers work. They want to use computers, but don’t care about how computers operate.

I will not cover how computers work in this topic, but want to remind everyone that when we designed computers back in 50s and 60s, one purpose was that it could help us to solve some of the complex problems we face. Computers have exceeded the expectations and there is a speculation that in near future, all mundane jobs will be replaced by artificial intelligence. Artificial intelligence is only possible when the programming continues to evolve and it has been. There are lot of curious people in our world and this mere mortal is one of them. For me, it was curiosity that drove towards computers and slowly i embraced the internals and ideas about computer. It was fascinating always. To answer the question, in short, to continually evolve as mankind, we need technology and technology is the fastest evolving paradigm which is majorly based on programming.

What’s your purpose for programming?

You don’t really need a purpose to program. I started with programming mundane algebraic functions . It was continuous improvement from that moment to solve some of the complex mathematics problems to engineering problems to real world business problems. Despite all that, there are lot of system level problems in computers that need attention. You can even choose a purpose of fun. Lot of programmers started programming for fun and built some of the coolest games. No purpose is still a purpose till the time you allocate certain time to improve your skill. It’s been 15 years from the time I have graduated from college, but I have not stopped programming and I am no where close to say that I am the best. You will never be the best, you will continually improve and that’s the aim you should have. Learn from all sources.

How to learn the skill of programming?

This is a broad topic. Learning how to learn itself covers lot of intricacies. How to learn programming. I will try to narrow down discussion about this in few steps

  1. Learn basic syntax, but not all of the syntax. You will learn this over the time.
  2. Learn programming principles, mostly object oriented principles.
  3. Find out common patterns and study them. In software engineering, we follow lot of design patterns and they get used all the time while designing any application.
  4. Find out common libraries in the language that you want to learn.
  5. If you are learning Java, definitely read Effective JavaClean code and Refactoring.
  6. Try pair programming where you work with another programmer.
  7. Read, read and read lots of code – bad code to good code both.
  8. Fall in love with learning to program, process over results.
  9. If you take up a project, start with MVP (Minimum Viable Product), get feedback from peers/customers and then improve on the product you are building. While following this process, you will improve your programming as well. You will hit road blocks, that will challenge you to find out the solution on your own. Balance long term process (learning programming) with short term goals (projects that you will work on).
  10. If you work with senior programmers, get a feedback for your code.

Resources for programming

  1. Solve problems on HackerRank
  2. Free code camp – Freecodecamp
  3. Participate in hackathons
  4. Write blogs about your insights

Conclusion

In this post, I tried to simplify a process about how to learn programming, and how to improve the skill of programming. I hope this post helps all those who are on the fence about programming to take up programming.

A collection with cascade=”all-delete-orphan” was no longer referenced by the owning entity instance

Introduction

Hibernate is an ORM provider. ORM is an object-relationship mapper. Hibernate Persistent class takes the values from the Java class attributes and persists them in the database.

Problem Statement

So recently I came across an interesting issue while working on hibernate persistence. I had an object certificate which had a child collection object certificateProperties. While updating an object that refers to certificate, it keeps throwing an error as below:

A collection with cascade="all-delete-orphan" was no longer referenced by the owning entity instance: com.betterjavacode.model.Certificate.certificateProperties; nested exception is org.hibernate.HibernateException: A collection with cascade="all-delete-orphan" was no longer referenced by the owning entity instance: com.infor.security.sts.config.model.Certificate.certificateProperties
 at org.springframework.orm.jpa.vendor.HibernateJpaDialect.convertHibernateAccessException(HibernateJpaDialect.java:333)
 at org.springframework.orm.jpa.vendor.HibernateJpaDialect.translateExceptionIfPossible(HibernateJpaDialect.java:244)
 at org.springframework.orm.jpa.JpaTransactionManager.doCommit(JpaTransactionManager.java:521)
 at org.springframework.transaction.support.AbstractPlatformTransactionManager.processCommit(AbstractPlatformTransactionManager.java:765)
 at org.springframework.transaction.support.AbstractPlatformTransactionManager.commit(AbstractPlatformTransactionManager.java:734)
 at org.springframework.transaction.interceptor.TransactionAspectSupport.commitTransactionAfterReturning(TransactionAspectSupport.java:518)
 at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:292)
 at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:96)
 at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
 at org.springframework.dao.support.PersistenceExceptionTranslationInterceptor.invoke(PersistenceExceptionTranslationInterceptor.java:136)
 at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
 at org.springframework.data.jpa.repository.support.CrudMethodMetadataPostProcessor$CrudMethodMetadataPopulatingMethodInterceptor.invoke(CrudMethodMetadataPostProcessor.java:133)
 at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
 at org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:92)
 at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
 at org.springframework.data.repository.core.support.SurroundingTransactionDetectorMethodInterceptor.invoke(SurroundingTransactionDetectorMethodInterceptor.java:57)
 at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
 at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:213)
 at com.sun.proxy.$Proxy213.save(Unknown Source)

It was surprising to see this error randomly popping up. I was wondering if I missed orphanRemoval tag on my object certificate for certificateProperties, but it was there. So definitely it was not the issue. Also to remember, I was using cascade = CascadeType.ALL for cascading persistence of certificate.

Solution

Now if you notice, hibernate gives enough information about the error to notice what is happening. Hibernate is complaining that it is not able to track the change for the child collection object certificateProperties while it is getting set in the parent object certificate. Hibernate requires that parent object owns a child collection object completely.

To fix this issue, the solution was simple

Old Code

    public void setCertificateProperties(Set<CertificateProperty> certificateProperties)
    {
        this.certificateProperties = certificateProperties; 
    }

Solution Code
    private Set<CertificateProperty> certificateProperties = new HashSet<>();

    public void setCertificateProperties(Set<CertificateProperty> certificateProperties)
    {
        this.certificateProperties.addAll(certificateProperties);
    }

 

Conclusion

We showed how hibernate can handle the persistence in the cascade operation. If you enjoyed this post, please subscribe to my blog here.