Thursday, December 07, 2006

Hibernate mapping legacy data

I recently encountered this while working with Hibernate. Mapping legacy data where foreign key does not refer to a primary key of the associated table is complex and is not generated correctly using many of the IDE's out there. You basically have to do some tweakings to make it work.

Two cases arise:
1) when foreign key refers to a unique key of the associated table
2) when foreign key refers to a non-primary/non-unique key

You will get an error of similar sort when mapping without the tweakings in the above cases:

[java] org.hibernate.MappingException: Foreign key (FK6771BFAA1845E8B:CardField [])) must have same number of columns as the referenced primary key (Card [project_id])
> [java] at org.hibernate.mapping.ForeignKey.alignColumns(ForeignKey.java:90)
> [java] at org.hibernate.mapping.ForeignKey.alignColumns(ForeignKey.java:73)
> [java] at org.hibernate.cfg.Configuration.secondPassCompileForeignKeys(Configuration.java:1182)
> [java] at org.hibernate.cfg.Configuration.secondPassCompile(Configuration.java:1089)
> [java] at org.hibernate.cfg.AnnotationConfiguration.secondPassCompile(AnnotationConfiguration.java:302)
> [java] at org.hibernate.cfg.Configuration.buildMappings(Configuration.java:1034)


The trick is to utilize the "property-ref" attribute to solve the above mapping issue.

Consider you have two tables:
Employee (emp_ID, emp_SSN, emp_Name)
Manager (mgr_SSN, mgr_Id)

In employee table empID is the primary key and empSSN is unique. Manager table has a many-to-one relation with the employee table with one manager can be assigned to multiple departments.

In Employee.hbm.xml file the empSSN would be defined like this:

<property name="empSSN" type="java.lang.Integer">
     <column name="emp_SSN" not-null="true" unique="true" />
</property>

<set name="managers" inverse="true">
     <key property-ref="empSSN">
          <column name="mgr_SSN" not-null="true" />
     </key>
     <one-to-many class="com.hibernate.mapping.Manager"/>
</set>

In manager.hbm.xml the property will be defined like this

<property name="mgrSSN" type="java.lang.Integer">
     <column name="mgr_SSN" not-null="true" />
</property>

<many-to-one name="employee" class="com.hibernate.mapping.Employee" update="false" insert="false" fetch="select" property-ref="empSSN" column="mgr_SSN" />


This should make it work!!!


Some other resources:

Post on Serverside
Hibernate Docs

Tuesday, August 29, 2006

SSL setup with MSN Adcenter

I will be posting a series of blogs on my experiences with working on a project utilizing the Microsoft adcenter as I encounter them. Let me share my experience with the security set up I struggled with initially

Platform: Linux
environment: J2EE

I kept getting the error

javax.net.ssl.SSLHandshakeException: sun.security.validator.ValidatorException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
Caused by: sun.security.validator.ValidatorException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target


in the initial stage. The first time I encountered this error was during the WSDL to JAVA source creation. The WSDL's are hosted on a secure site (https://beta6.api.idss.msn.com/v2) and thus needed the certs to be stored in the keystore. I circumvented it by downloading the WSDL's from browser and supplying local file URL as parameter to axis's WSDL2Java utility and that created the source files.

The error came back to haunt me as the webservice is also hosted on a secure site. I downloaded the certificate from the adcenter UI on sandbox (https://beta1.idss.msn.com/) using IE browser

(Double click the SSL lock icon in the bottom pane in the IE browser --> Details tab --> Copy to file --> [[format]] DER X.509)

and stored the cert in my local keystore using the command

keytool -import -file [[saved cert file loc]] -alias sandbox_api_cert -keystore MSN_Keystore
VM Arguments:
-Djavax.net.ssl.trustStore = [[keystore location]]
-Djavax.net.ssl.trustStorePassword = [[passwd]]

However this did not solve the problem.

On further research I found that "if you use a certificate not signed by a pre-installed certificate authority (=root cert), you need to import both your cert and the root cert". I checked the browser to see the root cert

(Double click the SSL lock icon in the bottom pane in the IE browser --> Certification Path tab)

and voila!!!! the cert was internally chained 3 times (GTE CyberTrust Global Root --> Microsoft Internet Authority --> Microsoft Secure Server Authority --> Beta1.idss.msn.com). I had already entered the cert for Beta1.idss.msn.com in my local keystore (as explained above) and so I proceeded to check if the certs for the other chain members are available in the jdk1.5.0_04/jre/lib/security/cacerts file using the command

keytool -v -list -keystore cacerts | grep gte
Enter keystore password: changeit
Alias name: gtecybertrustglobalca
Alias name: gtecybertrustca
Alias name: gtecybertrust5ca

keytool -v -list -keystore cacerts -alias gtecybertrustglobalca
Enter keystore password: changeit
Alias name: gtecybertrustglobalca
Creation date: May 10, 2002
Entry type: trustedCertEntry

Owner: CN=GTE CyberTrust Global Root, OU="GTE CyberTrust Solutions, Inc.", O=GTE Corporation, C=US
Issuer: CN=GTE CyberTrust Global Root, OU="GTE CyberTrust Solutions, Inc.", O=GTE Corporation, C=US
Serial number: 1a5
Valid from: Wed Aug 12 17:29:00 MST 1998 until: Mon Aug 13 16:59:00 MST 2018
Certificate fingerprints:
MD5: CA:3D:D3:68:F1:03:5C:D0:32:FA:B8:2B:59:E8:5A:DB
SHA1: 97:81:79:50:D8:1C:96:70:CC:34:D8:09:CF:79:44:31:36:7E:F4:74

keytool -v -list -keystore cacerts | grep microsoft
Enter keystore password: changeit

So the middle chain members Microsoft Internet Authority --> Microsoft Secure Server Authority were not available in my cacerts file. I went ahead and downloaded these certs from the browser

(Double click the SSL lock icon in the bottom pane in the IE browser --> Certification Path tab --> click on each certicate --> View Certificate)

and follow the procedure above to save and enter the cert into local keystore. Once I did this the previous problem was resolved however I was getting a new error

"java.security.cert.CertPathValidatorException: signature check failed"

I was pretty sure that one of my certs was wrong so I checked the WSDL to see where the webservice was hosted and it was different from where the UI was hosted. It was hosted on https://beta6.api.idss.msn.com. So I went ahead and downloaded the cert and stored it under local keystore and this resolved all the SSL errors.