Pokazywanie postów oznaczonych etykietą spring security. Pokaż wszystkie posty
Pokazywanie postów oznaczonych etykietą spring security. Pokaż wszystkie posty

23 lutego 2009

NetBeans 6.7 zamiast NetBeans 7.0 i Spring Security w 15 minut

0 komentarzy
Pojawił się komunikat o nowych wersjach NetBeans IDE numerowanych...6.7. Skąd ta zmiana w numeracji? I to jeszcze na mniejszą? A pikanterii dodaje jeszcze przeskok z 6.5 na 6.7. Wyjaśnienia można szukać w komunikacie "Message from the NetBeans Team - Why NetBeans 6.7?", z czego najważniejsze to:

To get innovation and quality improvements out to the community faster, and to have the NetBeans IDE be better aligned with the release schedules of other technologies that it supports, we have decided to concentrate on a series of smaller releases rather than the traditional two big releases per year.

oraz

NetBeans 6.7 is scheduled for release in June 2009. The main features are Maven and Kenai integration, and there are many smaller features that you can read about on the New and Noteworthy page. Java EE 6 support is planned for a future release. NetBeans 6.7 Milestone 2 is due out next week. We encourage you to download the release when it becomes available and to give us your feedback.

Dzięki temu całemu "zamieszaniu" ze zmianą wersji, kilka rzeczy poukładałem sobie w głowie, bo pytanie o wersję pojawiło się po pojawieniu się zgłoszenia Change cluster nb7.0 to nb6.7. Miałem w ten sposób okazję powyjaśniać sobie wiele z pojęć NetBeans, chociażby cluster. Jeśli dobrze rozumiem, pojęcie cluster oznacza zbiór modułów (ang. NBM - NetBeans Modules) w NetBeans (potwierdza to chociażby What is a Cluster?). Już podczas instalacji modułów JavaFX zauważyłem, że w katalogu domowym NetBeans tworzony jest katalog javafx2 (nie mam niestety pojęcia skąd ta dwójka?!). Spodziewałem się jednak, że w takim klastrze nb67 znajdę moduły, a tam...niewiele. Znalazłem jednak pliki graficzne (PNG) dla ekranu powitalnego i logo NetBeans w różnych rozmiarach. Wystarczy zajrzeć do nb6.7/core/locale/core_nb.jar, a w nim do org/netbeans/core/startup, gdzie mamy (zrzut z wersji rozwojowej z 23. stycznia):
 jlaskowski@work /cygdrive/c/apps/netbeans/nb6.7/core/locale
$ jar -tf core_nb.jar org/netbeans/core/startup/
org/netbeans/core/startup/
org/netbeans/core/startup/Bundle_nb.properties
org/netbeans/core/startup/about_nb.png
org/netbeans/core/startup/frame32_nb.gif
org/netbeans/core/startup/frame48_nb.gif
org/netbeans/core/startup/frame_nb.gif
org/netbeans/core/startup/splash_nb.gif
Zamiast zrzutów ekranu, aby umieścić logo lub ekran powitalny NetBeans, można po prostu sięgnąć do odpowiedniego pliku w klastrze nb67.

Dla zainteresowanych tematyką bezpieczeństwa w aplikacjach webowych z użyciem Spring Framework, Spring Security (dawne Acegi) i rozwojowego NetBeans 6.7 zapraszam do lektury artykułu wprowadzającego Proste uwierzytelnianie i autoryzacja w aplikacji webowej ze Spring Security w 15 minut. Kolejny artykuł zaplanowałem z użyciem CAS i LDAP.

Zastanawiam się, czy tego typu wiedzę nie łatwiej byłoby przyswoić w postaci filmu (z Wink czy podobnie). Dla mnie łatwiej byłoby stworzyć film, ale z oczywistych względów nie będzie można go wydrukować. Mam wrażenie, że w tym przypadku oglądanie krótkiego filmu instruktażowego byłoby mniej męczące niż czytanie artykułu ze zrzutami ekranów. Zapraszam do ankiety Czy artykuł z dużą ilością zrzutów ekranów nie powinien być filmem?, w której zbieram głosy przez kolejny tydzień.

19 lutego 2009

Podział konfiguracji springowej i automatyczny formularz logowania w Spring Security

0 komentarzy
Ostatnimi czasy zajmowałem się niezwykle interesującym tematem wykorzystania JA-SIG Central Authentication Service (CAS) oraz LDAP w ramach aplikacji webowej i natychmiast wskazałem na Spring Security jako platformę integracyjną. CAS dostarczał mechanizmu pojedyńczego uwierzytelnienia (ang. SSO - Single Sign-On), a LDAP informacji o użytkownikach i ich rolach (autoryzacja). O całym przedsięwzięciu później, ale teraz jedynie wspomnę, że podczas konfiguracji Spring Security (co w zasadzie dotyczy jakiegokolwiek projektu korzystającego ze Spring Framework) natrafiłem na ciekawą cechę konfiguracyjną - podział pliku applicationContext na oddzielne pliki, które w całości stanowią konfigurację springową aplikacji (patrz 15.2. Common configuration). Wystarczy zatem umieścić pewne części konfiguracji w oddzielnych plikach i można uprościć jej zarządzanie - w pliku WEB-INF/web.xml aplikacji webowej wystarczy użyć wyrażenia regularnego /WEB-INF/applicationContext*.xml, aby wskazać na nie wszystkie.
 <context-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/applicationContext*.xml</param-value>
</context-param>
Spring Framework zadba o ich połączenie i w ten sposób pozbywamy się choć części trudności w obsłudze tego xmlowego szaleństwa w Springu.

Kolejną ciekawostką, tym razem bezpośrednio związaną ze Spring Security, które przypomina mi Grails, jest automatyczne tworzenie formularza logowania (strony do podawania loginu i hasła). Wystarczy wdrożyć minimalną konfigurację Spring Security w naszej aplikacji webowej (patrz 2.2. Getting Started with Security Namespace Configuration), w której możemy skorzystać z 2.2.2.2. Form and Basic Login Options:

You might be wondering where the login form came from when you were prompted to log in, since we made no mention of any HTML files or JSPs. In fact, since we didn't explicitly set a URL for the login page, Spring Security generates one automatically, based on the features that are enabled and using standard values for the URL which processes the submitted login, the default target URL the user will be sent to and so on.

Podkreślam "Spring Security generates one automatically". Idealne na szybki start! I faktycznie działa!

13 stycznia 2009

Spring Security z CAS w aplikacji webowej

0 komentarzy
Zabrałem się za acegi z Grails, ale coś mi nieszło, więc zszedłem na poziom samego Acegi, a właściwie to Spring Security 2.0.4 w "zwykłych" aplikacjach webowych z użyciem facelets. Instrukcja w Tutorial: Adding Security to Spring Petclinic zadziałała bezbłędnie. Przykładowy projekt, który zabezpieczałem Spring Security zarządzany jest przez Apache Maven, więc nie kopiowałem bibliotek, a jedynie zdefiniowałem konieczne zależności w pom.xml:
 <properties>
<spring-security.version>2.0.4</spring-security.version>
</properties>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-core</artifactId>
<version>${spring-security.version}</version>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-core-tiger</artifactId>
<version>${spring-security.version}</version>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjrt</artifactId>
<version>1.6.2</version>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-cas-client</artifactId>
<version>${spring-security.version}</version>
</dependency>
i dodałem /WEB-INF/applicationContext-security.xml:
 <?xml version="1.0" encoding="UTF-8"?>

<beans:beans xmlns="http://www.springframework.org/schema/security"
xmlns:beans="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-2.0.xsd
http://www.springframework.org/schema/security
http://www.springframework.org/schema/security/spring-security-2.0.1.xsd">

<http auto-config="true">
<intercept-url pattern="/**" access="ROLE_USER"/>
</http>
<!--
Usernames/Passwords are
rod/koala
dianne/emu
scott/wombat
peter/opal
-->
<authentication-provider>
<password-encoder hash="md5"/>
<user-service>
<user name="rod" password="a564de63c2d0da68cf47586ee05984d7"
authorities="ROLE_SUPERVISOR, ROLE_USER, ROLE_TELLER"/>
<user name="dianne" password="65d15fe9156f9c4bbffd98085992a44e" authorities="ROLE_USER,ROLE_TELLER"/>
<user name="scott" password="2b58af6dddbd072ed27ffc86725d7d3a" authorities="ROLE_USER"/>
<user name="peter" password="22b5c9accc6e1ba628cedc63a72d57f8" authorities="ROLE_USER"/>
</user-service>
</authentication-provider>

</beans:beans>
Prawie tak jak opisano w dokumencie, poza wymaganiem, że wszystkie strony <intercept-url pattern="/**" access="ROLE_USER"/> są chronione. Jest jednak drobny błąd w dokumentacji, która wymaga, aby zdefiniować /WEB-INF/applicationContext-security.xml w context-param w deskryptorze wdrożenia web.xml, podczas gdy przez cały dokument mówi się o applicationContext-security-ns.xml. Już zgłosiłem jako SEC-1079 applicationContext-security.xml in Tutorial: Adding Security to Spring Petclinic.

Pozostało zabrać się za CASowanie mojej przykładowej aplikacji. Zabrałem się za 3.4. CAS Sample, a tam...dwa (drobne?) błędy. Pierwszy to wskazanie na dokument z opisem jak pobrać źródła "...as described in the introduction.":

Not Found
The requested URL /spring-security/site/reference/html/get-source was not found on this server.


a kiedy już dobrałem się do właściwego dokumentu 1.4. Getting the Source okazało się, że http://acegisecurity.svn.sourceforge.net/svnroot/acegisecurity/spring-security/trunk/ jest już nieaktualny i faktycznie powinien być https://src.springframework.org/svn/spring-security/trunk
. Niezły bałagan! Zgłosiłem jako SEC-1080 3.4. CAS Sample refers to incorrect get-source document and incorrect svn repo URL. Warto odnotować, jak szybko nastąpiła reakcja ze strony członków zespołu Spring Security - niecała godzina i już znalazł się chętny do wdrożenia poprawek!

Wracając do CAS i Spring Security, w porównaniu z poprzednią konfiguaracją teraz to beans jest wiodącą przestrzenią nazw (poprzednio security). To jest akurat niewielka zmiana i wyłącznie dotyczy organizacji pliku xmlowego niż samej konfiguracji Spring Security.
 <?xml version="1.0" encoding="UTF-8"?>

<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:sec="http://www.springframework.org/schema/security"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-2.0.xsd
http://www.springframework.org/schema/security
http://www.springframework.org/schema/security/spring-security-2.0.1.xsd">

<sec:http entry-point-ref="casProcessingFilterEntryPoint">
<sec:intercept-url pattern="/**" access="ROLE_USER" requires-channel="https"/>
</sec:http>
<sec:authentication-manager alias="authenticationManager"/>

<bean id="casProcessingFilter" class="org.springframework.security.ui.cas.CasProcessingFilter">
<sec:custom-filter after="CAS_PROCESSING_FILTER"/>
<property name="authenticationManager" ref="authenticationManager"/>
<property name="authenticationFailureHandler">
<bean class="org.springframework.security.ui.SimpleUrlAuthenticationFailureHandler">
<property name="defaultFailureUrl" value="/casfailed.jsp"/>
</bean>
</property>
<property name="authenticationSuccessHandler">
<bean class="org.springframework.security.ui.SimpleUrlAuthenticationSuccessHandler">
<property name="defaultTargetUrl" value="/"/>
</bean>
</property>
<property name="proxyGrantingTicketStorage" ref="proxyGrantingTicketStorage" />
<property name="proxyReceptorUrl" value="/secure/receptor" />
</bean>

<bean id="casProcessingFilterEntryPoint" class="org.springframework.security.ui.cas.CasProcessingFilterEntryPoint">
<property name="loginUrl" value="https://localhost:9443/cas/login"/>
<property name="serviceProperties" ref="serviceProperties"/>
</bean>

<bean id="casAuthenticationProvider" class="org.springframework.security.providers.cas.CasAuthenticationProvider">
<sec:custom-authentication-provider />
<property name="userDetailsService" ref="userService"/>
<property name="serviceProperties" ref="serviceProperties" />
<property name="ticketValidator">
<bean class="org.jasig.cas.client.validation.Cas20ServiceTicketValidator">
<constructor-arg index="0" value="https://localhost:9443/cas" />
<property name="proxyGrantingTicketStorage" ref="proxyGrantingTicketStorage" />
<property name="proxyCallbackUrl" value="https://localhost:8443/cas-sample/secure/receptor" />
</bean>
</property>
<property name="key" value="an_id_for_this_auth_provider_only"/>
</bean>

<bean id="proxyGrantingTicketStorage" class="org.jasig.cas.client.proxy.ProxyGrantingTicketStorageImpl" />

<bean id="serviceProperties" class="org.springframework.security.ui.cas.ServiceProperties">
<property name="service" value="https://localhost:8443/cas-sample/j_spring_cas_security_check"/>
<property name="sendRenew" value="false"/>
</bean>

<sec:user-service id="userService">
<sec:user name="rod" password="rod" authorities="ROLE_SUPERVISOR,ROLE_USER" />
<sec:user name="dianne" password="dianne" authorities="ROLE_USER" />
<sec:user name="scott" password="scott" authorities="ROLE_USER" />
</sec:user-service>
</beans>
Nie podoba mi się odwołanie do https://localhost:8443/cas-sample w pliku konfiguracyjnym. Niby jest do zmiany podczas wdrażania aplikacji, ale wystarczy zmiana kontekstu webowego i już muszę pamiętać, aby zmienić coś w deskryptorze (!) Tutaj oczekiwałbym jakiejś zmiany.

Jeszcze tylko zmiana w web.xml i rozpoczynam testowanie.

Testy zakończyły się niepowodzeniem:
 Caused by: org.springframework.beans.factory.CannotLoadBeanClassException: 
Cannot find class [org.springframework.security.ui.SimpleUrlAuthenticationFailureHandler] for
bean with name 'org.springframework.security.ui.SimpleUrlAuthenticationFailureHandler#e3f429'
defined in ServletContext resource [/WEB-INF/applicationContext-security.xml]
bo klasa org.springframework.security.ui.SimpleUrlAuthenticationFailureHandler dostępna jest dopiero od wersji Spring Security 2.5.0-SNAPSHOT. Aby z niej skorzystać należy rozbudować konfigurację pom.xml o
 <build>
<extensions>
<extension>
<groupId>org.springframework.aws</groupId>
<artifactId>spring-aws-maven</artifactId>
<version>1.2.2</version>
</extension>
</extensions>
</build>
<repositories>
<repository>
<id>spring-snapshot</id>
<name>Spring Snapshot Repository</name>
<url>s3://maven.springframework.org/snapshot</url>
<snapshots>
<enabled>true</enabled>
</snapshots>
</repository>
</repositories>
Po tym posypało się większymi uaktualnieniami, gdyż
 11:09:55,421 WARN  [BasicLifecycleMonitor] Exception occured while notifying listener
java.lang.NoClassDefFoundError: org/springframework/beans/factory/config/BeanExpressionResolver
Zdaje się, że jest to pierwszy raz, kiedy przyjdzie mi skorzystać ze Spring Framework 3.0.0.M1, bo ta klasa dopiero w tej wersji się pojawiła - org.springframework.beans.factory.config.BeanExpressionResolver. W takiej sytuacji mam dwa podejścia - brnąć dalej w uaktualnienia licząc, że ze zmianami nie przyjdzie mi zajmować się problemami, które wynikają z błędów w oprogramowaniu, a nie mojej nieznajomości Spring Security, albo po prostu doczytać, co należy zmienić, aby nie korzystać z nowości Spring Security 2.5.0-SNAPSHOT. Na razie wybieram podejście pierwsze - brnę dalej (i cichutko się modlę).

W komentarzach do komunikatu o Spring Framework 3.0.0.M1 można znaleźć odpowiedź dla poszukujących repozytorium mavenowego dla tego wydania.

Przede wszystkim zmieniamy artifactId na odpowiadający pakietowi (konwencja zapożyczona z nazewnictwa pakunków OSGi, którą SpringSource krzewi przez Spring-DM, a następnie SpringSource dm Server) i dodajemy odpowiednie repozytoria:
 <properties>
<spring.version>3.0.0.M1</spring.version>
</properties>
...
<repository>
<id>SpringSource Enterprise Bundle Repository - External Bundle Milestones</id>
<url>http://repository.springsource.com/maven/bundles/milestone</url>
</repository>
<repository>
<id>SpringSource Enterprise Bundle Repository - SpringSource Bundle Releases</id>
<url>http://repository.springsource.com/maven/bundles/release</url>
</repository>
<repository>
<id>SpringSource Enterprise Bundle Repository - External Bundle Releases</id>
<url>http://repository.springsource.com/maven/bundles/external</url>
</repository>
...
<dependency>
<groupId>org.springframework</groupId>
<artifactId>org.springframework.core</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>org.springframework.web</artifactId>
<version>${spring.version}</version>
</dependency>
Zbudować zbudowałem, ale przy uruchomieniu aplikacji pojawił się komunikat o niedostępności org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean, więc dodałem kolejną zależność do projektu:
 <dependency>
<groupId>org.springframework</groupId>
<artifactId>org.springframework.orm</artifactId>
<version>${spring.version}</version>
</dependency>
Ponownie budowanie i wdrożenie do Geronimo. Teraz jest cacy! Nawet działa! Coś jeszcze będę musiał poczytać o CASie (albo przegadać temat z Michałem Margielem, który oferował swoją pomoc w temacie - podobno się zna ;-)).

Oczywiście korzystając z atrybutu autowire możnaby znacząco uprościć plik konfiguracyjny Springa applicationContext-security.xml, gdzie wiązania typu <property name="authenticationManager" ref="authenticationManager"/> byłyby tworzone dynamicznie przez Spring Framework.