blog.smart-java.nl
Ordina J-Technologies – Java Blog

Archief voor December, 2009




Spring Security 3.0 and CAS 3.3.4 integration

Door: Stephan Oudmaijer, 29 December 2009


JA-SIG Central Authentication Service (CAS) is an enterprise level, open-source, single sign on solution with a Java server component and various client libraries written in a multitude of languages including PHP, PL/SQL, Java, .Net, PHP, Perl and more.

Both Spring Security 3.0 and Spring 3.0 where released this month. Spring Security provides excelent support for CAS. In Spring Security 3.0 a couple of CAS integration components have been changed (renamed). The configuration is also a bit different from Spring Security 2.0.x.

How CAS works
The CAS Server webapp should be deployed on an application server. Applications can use the CAS Server for the authentication process. CAS only provides authentication and no authorisation. The authorisation should be implemented (using Spring Security) by the applications using the CAS Server.

How Spring Security fits in
Lets say an user tries to access a protected resource within an application using Spring Security. Spring Security intercepts the request and checks if the user should be authenticated. If so, the user is forwarded tot the CAS login page. The users typically enters his username and password and submits it to the CAS server. If the user was successfully authenticated by CAS, the users will be redirected back to the application where it was accessing a protected resource. The redirect URL now contains a ticket generated by CAS. Spring Security will use this ticket to validate against CAS if the ticket is valid for this user. If so, the user details will be loaded by Spring Security. If the user is also authorised to access the protected resource, access will be granted.

Configuration
For my demo I use the CAS server webapp version 3.3.4. I have it deployed on Apache Tomcat 6.0.20. In the demo I access the CAS Server using HTTP, this should be HTTPS in a production environment! I have deployed the applications using the following URLs:

  • The CAS Server web application: http://localhost:8080/cas-server-webapp-3.3.4/
  • The application using CAS: http://localhost:8080/spring-security-cas/
  • I use Maven2 for managing my dependencies, the following libraries should be added to the pom.xml.

    Maven2 dependencies

    
    	
    		org.springframework
    		spring-core
    		3.0.0.RELEASE
    		false
    	
    	
    		org.springframework
    		spring-webmvc
    		3.0.0.RELEASE
    		false
    	
    	
    		org.springframework.security
    		spring-security-core
    		3.0.0.RELEASE
    		false
    	
    	
    		org.springframework.security
    		spring-security-config
    		3.0.0.RELEASE
    		false
    	
    	
    		org.springframework.security
    		spring-security-cas-client
    		3.0.0.RELEASE
    		false
    	
    
    

    Spring Security configuration
    Please be aware that the Spring Security reference documentation is not 100% accurate on the CAS integration.

    
    
    
    	
    	
    		
    		
    	
    
    	
    	
    		
    	
    
    	
    	
    
    
    		
    
            
    	
    
    	
    
    	
    	
    
    
    	
    
    	
    	
    
    
    
    			
    				
    			
    		
    
    	
    
    	
    	
    		
    	
    
    

    web.xml

    
    
    	webapp
    
    	
    contextConfigLocation
    /WEB-INF/applicationContext-security.xml
    	
    
    org.springframework.web.context.ContextLoaderListener
    	
    
    	
    		springSecurityFilterChain
    		org.springframework.web.filter.DelegatingFilterProxy
    	
    	
    		springSecurityFilterChain
    		/*
    	
    
    	
    		index.html
    		index.jsp
    	
    
    

    Thats it, try it yourself!

    Original article posted at: http://oudmaijer.com




    A lot of exciting new stuff in december: Spring 3.0 & Java EE 6

    Door: Stephan Oudmaijer, 21 December 2009

    The last month of 2009 has brought some exciting Java news, both Java EE 6 and Spring 3.0 have become final this month!

    Spring Framework 3.0 GA

    Spring 3.0 GA is compatible with Java EE 6 final in terms of runtime environments now (e.g. on GlassFish v3 as released last week) and supports JPA 2.0 final already (e.g. using EclipseLink 2.0). We also support the newly introduced @ManagedBean (JSR-250 v1.1) annotation for component scanning now, which nicely complements our @Inject (JSR-330) support for annotation-driven dependency injection.

    * Spring expression language (SpEL): a core expression parser for use in bean definitions, allowing for references to nested bean structures (e.g. properties of other beans) as well as to environmental data structures (e.g. system property values) through a common #{…} syntax in property values.

    * Extended support for annotation-based components: now with the notion of configuration classes and annotated factory methods (as known from Spring JavaConfig). Spring also allows for injecting configuration values through @Value expressions now, referring to configuration settings via dynamic #{…} expressions or static ${…} placeholders.

    * Powerful stereotype model: allows for creating ’shortcut’ annotations through the use of meta-annotations, e.g. for default scopes and default transactional characteristics on custom stereotypes. Imagine a custom @MyService annotation indicating @Service, @Scope(“request”) and @Transactional(readOnly=true) through a single annotation.

    * Standardized dependency injection annotations: Spring 3.0 comes with full support for the JSR-330 specification for Dependency Injection in Java – annotation-driven injection via @Inject and its associated qualifier and provider model, as an alternative to Spring’s own @Autowired and co.

    * Declarative model validation based on constraint annotations: Spring-style setup of a JSR-303 Bean Validation provider (such as Hibernate Validator 4.0). Comes with an annotation-driven validation option in Spring MVC, exposing a unified view on constraint violations through Spring’s binding result facility.

    * Enhanced binding and annotation-driven formatting: Converter and Formatter SPIs as an alternative to standard PropertyEditors. Formatting may be driven by annotations in a style similar to JSR-303 constraints, e.g. using @DateTimeFormat. Also, check out the new mvc namespace for convenient setup of formatting and validation in Spring MVC.

    * Comprehensive REST support: native REST capabilities in Spring MVC, such as REST-style request mappings, URI variable extraction through @PathVariable parameters, and view resolution driven by content negotiation. Client-side REST support is available in the form of a RestTemplate class.

    * Rich native Portlet 2.0 support: Spring MVC fully supports Portlet 2.0 environments and Portlet 2.0’s new event and resource request model. Includes specialized mapping facilities for typical portlet request characteristics: @ActionMapping, @RenderMapping, @ResourceMapping, @EventMapping.

    * Object/XML Mapping (OXM): as known from Spring Web Services, now in Spring Framework core. Marshalling and Unmarshaller abstractions with out-of-the-box support for JAXB 2, Castor, etc. Comes with integration options for XML payloads in Spring MVC and Spring JMS.

    * Next-generation scheduling capabilities: new TaskScheduler and Trigger mechanisms with first-class cron support. Spring 3.0 comes with a convenient task namespace and also supports @Async and @Scheduled annotations now. This can be executed on top of native thread pools or server-managed thread pools.

    Java EE 6

    From Roberto Chinnici’s weblog:

    With the closing of the final approval ballot earlier today, it is now official: the JCP Executive Committee has given a green light to the release of the Java EE 6 platform specification. The final release will happen on December 10, when GlassFish v3 will be available. For more details of the ballot, with comments from several EC members, please refer to the JCP web site. Of course the excitement of the event drove me to watch live the ballot close at midnight PT and tweet about it!

    Several other Java EE component JSRs were approved at the same time: Servlet 3.0, JPA 2.0, EJB 3.1, Connector 1.6, CDI 1.0. All other components, be they full JSRs or maintenance releases (MRs, for insiders), had been previously approved. I should also mention here that, being part of the platform JSR (JSR-316) the Java EE 6 Web Profile too was approved, and so was the Managed Beans 1.0 specification I talked about in prior blog entries. So, yes, now we really have profiles in Java EE: let’s put them to good use!

    We are going to have more white papers, tutorials, etc. coming up for the final release in a few days. In the meantime, even a casual perusal of the javadocs will show a number of new APIs in key areas: JAX-RS, Dependency Injection, CDI, Bean Validation. I see a bright future for these APIs, and fully expect them to become key components of Java EE applications in the coming years. I also happen to think that the level of integration that we achieved between these new APIs and some of the existing ones represents a valuable principle that can guide the evolution of Java EE going forward; certainly I expect future Java EE APIs to be held to the same strict criteria for integration with the rest of the platform that JAX-RS, Bean Validation and CDI were held to in this release.

    Java EE 6 includes:

    • Java Persistency API 2.0
    • JavaServer Faces 2.0
    • Enterprise JavaBeans 3.1
    • Servlet 3.0
    • Context and Dependecy Injection (a.k.a. WebBeans)
    • Dependency Injection (@Inject)
    • JAX-RS
    • Web Profile
    • and much more…

    See also this article for more information: http://java.sun.com/developer/technicalArticles/JavaEE/JavaEE6Overview.html

    So if you are bored during the christmas holiday, you can try out the new Java EE 6 features using GlassFish v3 and NetBeans 6.8. But also IntelliJ 9 and Eclipse 3.5.1 feature Java EE 6 support.




    Sun Certified JSF Developer exam coming up?

    Door: Ron Thijssen, 16 December 2009

    Just received an email message from the jsr-314 mailing list, where Ed Burns states that he will be working on creating the new Sun Certified JSF Developer exam.

    Looking foreward on taking this examen when it’s finished, but first let’s submit some questions :)

    I’m going heads-down trying to help create the new Sun Certified JSF
    Developer exam (and accompanying course) so I’ll be slower than usual to
    respond to emails.

    If you need an immediate response, call me on my phone below.

    If you want to help out with the exam, submit questions here:
    <http://bit.ly/jsf2certexam>.

    Thanks for your understanding!

    Ed




    JPA 2.0 … finally final

    Door: Peter Schuler, 11 December 2009

    Thursday 10 December the people from EclipseLink release version 2.0 of their Object Relation Mapping framework. Besides other improvements this release includes the reference implementation of JPA 2.0.  This means that the JPA 2.0 and JSR-317 are now final!

    The second release of the Jave Persistence API adds a lot of new features to the JPA framework. The team responsible for this release now claims to serve 95% of the persistence needs of Java programmers. You can get the final version of JSR-317 or download the reference implementation on the eclipselink website. Two older blogs by Mike Keith introduces all the new features here and here.

    Version 2.0 now has (among others) support for:

    • Increased locking possibilities;
    • Support for Criteria Queries and a MetaModel;
    • (A little) support for second level caching;
    • Basic Element and embeddable collections;
    • Orphan removals for sets;
    • Derived Identifiers (using @ManyToOne as past of your primary key);
    • Ordered list.

    With these new features the Java Persistence API becomes even more useful. In the next  few weeks I will blog some more about the new features and go deeper into some of the new features and how to use them to your advantange.

    So stay tuned.




    Temporale data – deel 4: bitemporale collections

    Door: gnoij, 7 December 2009

    Het is alweer enige tijd geleden dat ik heb geschreven over temporale patterns. In dit deel wil ik het bitemporale pattern uitbreiden met bitemporale collections. Werd met de bitemporale property nog een enkele property historisch gemaakt, in dit deel maken we een lijst historisch. Dat wil zeggen dat er meerdere elementen van een historische lijst tegelijkertijd geldig kunnen zijn.

    De klasse BiTemporalObject uit het derde deel blijft hetzelfde. En naast de BiTemporalProperty voor enkelvoudige historische relaties krijgen we nu ook een klasse BiTemporalCollection voor meervoudige historische relaties.

    BiTemporalCollection

    public class BiTemporalCollection {
     
        protected List alleHistorischeVersies = new ArrayList();
     
        public BiTemporalCollection() {
            super();
        }
     
        public List getActueleVersies() {
            return getVersieOp(new Date(), new Date());
        }
     
        public List getVersieOp(final Date registratieTijdstip, final Date peilDatum) {
            return (List) CollectionUtils.select(this.alleHistorischeVersies, new Predicate() {
                public boolean evaluate(Object object) {
                    return ((BiTemporalObject) object).isGeldigOp(registratieTijdstip, peilDatum);
                }
            });
        }
     
        public void voegActueleVersieToe(BiTemporalObject actueleVersie) {
            if (actueleVersie == null) {
                throw new IllegalArgumentException("actueleVersie is null");
            }
            this.alleHistorischeVersies.add(actueleVersie);
        }
     
        public void wijzigActueleVersie(BiTemporalObject nieuweVersie, BiTemporalObject oudeVersie) {
            if (nieuweVersie == null) {
                throw new IllegalArgumentException("nieuweVersie is null");
            }
            if (oudeVersie == null) {
                throw new IllegalArgumentException("oudeVersie is null");
            }
            beeindigVorigeVersie(nieuweVersie, oudeVersie);
            this.alleHistorischeVersies.add(nieuweVersie);
        }
     
        private void beeindigVorigeVersie(final BiTemporalObject nieuweVersie, final BiTemporalObject oudeVersie) {
     
            BiTemporalObject afTeVoerenVersie = zoekActueleVersie(oudeVersie, nieuweVersie.getIngangsdatum(), nieuweVersie.getOpvoerTijdstip()); 
     
            if (afTeVoerenVersie == null) {
                throw new IllegalStateException("Geen oude actuele versie gevonden!");
            }
     
            beeindigVersie(afTeVoerenVersie, nieuweVersie.getIngangsdatum(), nieuweVersie.getOpvoerTijdstip());
        }
     
        public void beeindig(final BiTemporalObject actueleVersie, final Date einddatum) {
            BiTemporalObject afTeVoerenVersie = zoekActueleVersie(actueleVersie, einddatum, new Date());
            if (afTeVoerenVersie == null) {
                throw new IllegalStateException("Geen oude actuele versie gevonden!");
            }
            beeindigVersie(afTeVoerenVersie, einddatum, new Date());
        }
     
        public void beeindig(final Date einddatum) {
            List afTeVoerenVersies = (List) CollectionUtils.select(this.alleHistorischeVersies, new Predicate() {
                public boolean evaluate(Object object) {
                    BiTemporalObject versie = (BiTemporalObject) object;
                    return versie.isGeldigOp(new Date(), einddatum);
                }
            });
     
            CollectionUtils.forAllDo(afTeVoerenVersies, new Closure() {
                public void execute(Object input) {
                    beeindigVersie((BiTemporalObject) input, einddatum, new Date());
                }
            });
        }
     
        private void beeindigVersie(BiTemporalObject versie, Date einddatum, Date registratieTijdstip) {
            BiTemporalObject kopieVersie = versie.kopieer(einddatum, registratieTijdstip);
            this.alleHistorischeVersies.add(kopieVersie);
        }
     
        private BiTemporalObject zoekActueleVersie(final BiTemporalObject actueleVersie, final Date peildatum, final Date registratieTijdstip) {
            return (BiTemporalObject) CollectionUtils.find(this.alleHistorischeVersies, new Predicate() {
                public boolean evaluate(Object object) {
                    BiTemporalObject versie = (BiTemporalObject) object;
                    return versie.equals(actueleVersie) && versie.isGeldigOp(registratieTijdstip, peildatum);
                }
            });
        }

    De wijzigingen ten opzichte van de BiTemporalProperty uit het vorige deel zijn dat er nu niet één maar meer versies tegelijkertijd geldig kunnen zijn (getActueleVersies) en dat we versies kunnen toevoegen (voegActueleVersieToe) en kunnen wijzigen (wijzigActueleVersie). Bij deze laatste methode we de te wijzigen versie meegeven, zodat deze beëindigd kan worden en de nieuwe versie toegevoegd wordt. Ook kunnen we alle versies van de collection beëindigen (beeindig) of een enkele versie (die dan weer aan de methode meegegeven moet worden).

    Een voorbeeld

    In dit voorbeeld wordt het voorbeeld uit deel 3 uitgebreid met een manager (zelf ook een werknemer), die meerdere werknemers onder zich heeft.

    Manager

    public class Manager extends Werknemer {
     
        private static final long serialVersionUID = 1L;
     
        private BiTemporalCollection werknemers = new BiTemporalCollection();
     
        public Manager() {
            super();
        }
     
        public Manager(String naam) {
            super(naam);
        }
     
        public void voegWerknemerToe(Werknemer werknemer, Date ingangsdatum) {
            this.werknemers.voegActueleVersieToe(new WerknemerRelatie(werknemer, ingangsdatum));
        }
     
        public List getTeManagenWerknemers() {
            List relaties = getWerknemerRelaties();
            CollectionUtils.transform(relaties, new Transformer() {
                public Object transform(Object object) {
                    return ((WerknemerRelatie)object).getWerknemer();
                }
            }) ;
            return relaties;
        }
     
        public List getTeManagenWerknemers(Date registratieTijdstip, Date peildatum) {
            List relaties = getWerknemerRelaties(registratieTijdstip, peildatum);
            CollectionUtils.transform(relaties, new Transformer() {
                public Object transform(Object object) {
                    return ((WerknemerRelatie)object).getWerknemer();
                }
            }) ;
            return relaties;
        }
     
        public List getWerknemerRelaties() {
            return this.werknemers.getActueleVersies();
        }
     
        public List getWerknemerRelaties(Date registratieTijdstip, Date peildatum) {
            return this.werknemers.getVersieOp(registratieTijdstip, peildatum);
        }
     
        public void wijzigWerknemer(Werknemer nieuweWerknemer, Werknemer oudeWerknemer, Date wijzigingsdatum) {
            WerknemerRelatie nieuweRelatie = new WerknemerRelatie(nieuweWerknemer, wijzigingsdatum);
            WerknemerRelatie oudeRelatie = bepaalWerknemerRelatie(oudeWerknemer);
            this.werknemers.wijzigActueleVersie(nieuweRelatie, oudeRelatie);
        }
     
        private WerknemerRelatie bepaalWerknemerRelatie(final Werknemer werknemer) {
            return (WerknemerRelatie)CollectionUtils.find(this.werknemers.getActueleVersies(), new Predicate() {
                public boolean evaluate(Object obj) {
                    return ((WerknemerRelatie)obj).getWerknemer().equals(werknemer);
                }
            });
        }
     
        public void stopManagenVanWerknemer(Werknemer werknemer, Date einddatum) {
            WerknemerRelatie relatie = bepaalWerknemerRelatie(werknemer);
            this.werknemers.beeindig(relatie, einddatum);
        }
     
        public void stopManagen(Date einddatum) {
            this.werknemers.beeindig(einddatum);
        }
    }

    Deze klasse representeert de manager. Als een manager een werknemer gaat managen, wordt de werknemer toegevoegd aan de lijst van te managen werknemers (voegWerknemerToe). Als een werknemer wordt vervangen door een andere werknemer wordt de methode wijzigWerknemer aangeroepen, waardoor de relatie met de oude werknemer wordt beëindigd en de nieuwe werknemer wordt begonnen. Als een werknemer uit dienst gaat of naar een andere afdeling, stopt de manager met het managen van deze werknemer (stopManagenVanWerknemer), waardoor de historische relatie van de manager met de werknemer wordt beëindigd. Als de manager stopt met managen (stopManagen), wordt de relatie met alle gemanagede werknemers beëindigd.

    De historische relatie van de manager met de werknemer wordt gerepresenteerd door de klasse WerknemerRelatie.

    WerknemerRelatie

    public class WerknemerRelatie extends BiTemporalObject {
     
        private static final long serialVersionUID = 1L;
     
        private Werknemer werknemer;
     
        protected WerknemerRelatie() {
            super();
        }
     
        protected WerknemerRelatie(Werknemer werknemer, Date ingangsdatum) {
            super(ingangsdatum);
     
            this.werknemer= werknemer;
        }
     
        public Werknemer getWerknemer() {
            return this.werknemer ;
        }
    }

    De test ziet er als volgt uit:

    public void testManager() {
     
    	Manager jan = new Manager("Jan");
     
    	// simuleer de opvoer tijd 1-1-2003
    	Date aanvangsdatum = DateUtils.maakDate(2003, 1, 1);
    	BiTemporalObject.TEST_OPVOER_TIJDSTIP = aanvangsdatum; 
     
    	Afdeling inkoop = new Afdeling("Inkoop");
    	jan.setAfdeling(inkoop, aanvangsdatum);
     
    	Werknemer kees = new Werknemer("Kees");
    	kees.setAfdeling(inkoop, aanvangsdatum);
    	jan.voegWerknemerToe(kees, aanvangsdatum);
     
    	Werknemer piet = new Werknemer("Piet");
    	piet.setAfdeling(inkoop, aanvangsdatum);
    	jan.voegWerknemerToe(piet, aanvangsdatum);
     
    	assertEquals(2, jan.getTeManagenWerknemers().size());
    	assertTrue(jan.getTeManagenWerknemers().contains(kees));
    	assertTrue(jan.getTeManagenWerknemers().contains(piet));
     
    	Date wijzigingsdatum = DateUtils.maakDate(2006, 1, 1);
    	BiTemporalObject.TEST_OPVOER_TIJDSTIP = wijzigingsdatum; 
     
    	Werknemer johan = new Werknemer("Johan");
    	johan.setAfdeling(inkoop, wijzigingsdatum);
     
    	// Johan vervangt Piet, die uit dienst gaat
    	jan.wijzigWerknemer(johan, piet, wijzigingsdatum);
    	piet.uitDienst(wijzigingsdatum);
     
    	assertEquals(2, jan.getTeManagenWerknemers().size());
    	assertTrue(jan.getTeManagenWerknemers().contains(johan));
    	assertFalse(jan.getTeManagenWerknemers().contains(piet));
     
    	// jan managete gisteren piet nog wel
    	Date gisteren = DateUtils.maakDate(2005, 12, 31);
    	assertTrue(jan.getTeManagenWerknemers(new Date(), gisteren).contains(piet));
     
    	Date einddatum = DateUtils.maakDate(2009, 1, 1);
    	BiTemporalObject.TEST_OPVOER_TIJDSTIP = wijzigingsdatum; 
     
    	jan.stopManagenVanWerknemer(kees, einddatum);
    	kees.uitDienst(einddatum);
     
    	assertEquals(1, jan.getTeManagenWerknemers().size());
    	assertFalse(jan.getTeManagenWerknemers().contains(kees));
     
    	jan.stopManagen(einddatum);
    	assertTrue(jan.getTeManagenWerknemers().isEmpty());
    }

    In deze test maken we een manager Jan aan, die werkt op de afdeling Inkoop op 1 januari 2003. Vanaf deze dag begint hij ook met het managen van twee werknemers Kees en Piet. Vanaf 1 januari 2006 vervangt een nieuwe werknemer Johan Piet, die uit dienst gaat. Op 1 januari 2009 stopt Jan met het managen van al zijn werknemers.

    Hibernate mappings

    De hibernate mapping van de klasse WerknemerRelatie is analoog aan de mapping van de AfdelingRelatie uit deel 3.

    De mapping van de werknemer is uitgebreid met de subclass Manager, die de werknemers als BiTemporalCollection property mapt.

    Werknemer.hbm.xml

    <hibernate-mapping package="nl.ordina.bitemporal.example" default-access="field">
    	<class name="Werknemer" table="Werknemer" discriminator-value="Werknemer">
    		<id name="id" column="id">
    			<generator class="identity"></generator>
    		</id>
    		<discriminator column="type" />
    		<version name="versie" />
     
    		<!-- properties -->
    		<property name="naam" column="naam" />
     
    		<!-- de verwijzing naar de afdelingrelatie -->
    		<component name="afdelingRelatie" 
    			class="nl.ordina.temporal.bitemporal.BiTemporalProperty"
    			lazy="false">
    			<bag name="alleHistorischeVersies"
    				cascade="all, delete-orphan" >
    				<key column="werknemerId" />
    				<one-to-many
    					class="AfdelingRelatie" />
    			</bag>
    		</component>
     
    		<subclass name="Manager" discriminator-value="Manager">
    		<!-- de verwijzing naar de werknemerrelatie -->
    			<component name="werknemers" 
    				class="nl.ordina.temporal.bitemporal.BiTemporalCollection"
    				lazy="false">
    				<bag name="alleHistorischeVersies"
    					cascade="all, delete-orphan" >
    					<key column="managerId" />
    					<one-to-many
    						class="WerknemerRelatie" />
    				</bag>
    			</component>
    		</subclass>
    	</class>
    </hibernate-mapping>

    LET OP: In bovenstaand artikel wordt gesproken over BiTemporalCollection. Dit is niet dezelfde als de BiTemporalCollection van Fowler , wat eigenlijk de BiTemporalProperty uit deel 3 is.