Tworzenie WebService’ów z wykorzystaniem Axis2 JBoss® Seam: Simplicity and Power Beyond Java EE
Aug 29

Acegi jest to narzędzie służące zapewnieniu bezpieczeństwa w aplikacjach korporacyjnych. Zapewnia wszechstronne mechanizmy uwierzytelniania i autoryzacji.

Uwierzytelnianie i Autoryzacja

Są to podstawowe elementy zapewnienia bezpieczeństwa w aplikacji sieciowej. Uwierzytelnianie polega na potwierdzeniu tożsamości użytkownika, zwykle poprzez podanie loginu i hasła. Autoryzacja oznacza przyznanie określonemu użytkownikowi dostępu do pewnych zasobów.

Przykładowa Aplikacja

Kod źródłowy przykładowej aplikacji możecie pobrać tu. Wersja bez Acegi jest dostępna tutaj.

Acegi

Działanie Acegi polega na zastosowaniu szeregu filtrów. Dbają one o to aby użytkownik uzyskał dostęp do tych elementów, do których ma prawo. Działanie rozpoczyna sprawdzenie czy dany zasób jest zabezpieczony. Następnie sprawdza się czy użytkownik jest już zalogowany, jeśli nie zostanie o to poproszony w tym momencie. Po poprawnym zalogowaniu sprawdza się czy jest możliwy dostęp do zasobu, a następnie go udostępnia.

Konfiguracja

FilterChainProxy

Do połączenia zestawu filtrów w spójnie działającą całość użyjemy FilterChainProxy. Obiekt ten zajmie się utworzeniem i przygotowaniem potrzebnych filtrów.

<bean id="filterChainProxy" class="org.acegisecurity.util.FilterChainProxy">
	<property name="filterInvocationDefinitionSource">
		<value>CONVERT_URL_TO_LOWERCASE_BEFORE_COMPARISON
			PATTERN_TYPE_APACHE_ANT
			/**=httpSessionContextIntegrationFilter,
			formAuthenticationProcessingFilter,exceptionTranslationFilter,
			filterSecurityInterceptor</value>
	</property>
</bean>

Parametr filterInvocationDefinitionSource zapewnia przygotowanie poprawnych adresów oraz definiuje listę filtrów do zestawienia. Teraz przejdźmy do konfiguracji poszczególnych elementów.

AutenticationProcessingFilter

<bean id="formAuthenticationProcessingFilter" class="org.acegisecurity.ui.webapp.AuthenticationProcessingFilter">
	<property name="authenticationManager" ref="authenticationManager" />
	<property name="authenticationFailureUrl" value="/badlogin.jsp" />
	<property name="defaultTargetUrl" value="/" />
	<property name="filterProcessesUrl" value="/j_acegi_security_check" />
</bean>

Pierwszy filtr, do którego przyjdzie żądanie. Filtr ten zajmie się uwierzytelnieniem użytkownika poprzez wyświetlenie formularza z prośbą o podanie loginu i hasła, jednak nie zajmuje się potwierdzeniem ich poprawności. Te funkcje znajdziemy w kolejnych elementach.

HttpSessionContextIntegrationFilter

<bean id="httpSessionContextIntegrationFilter" class="org.acegisecurity.context.HttpSessionContextIntegrationFilter">
</bean>

Proste zadanie tego bean’a polega na przekazywaniu informacji dotyczących uwierzytelnienia pomiędzy kolejnymi żądaniami.

ExceptionTranslationFilter

Zadaniem tego komponentu jest przechwytywanie wyjątków związanych z uwierzytelnianiem i autoryzacją. Jeśli użytkownik jest niezalogowany, wyświetlony zostanie ekran logowania. Jeśli użytkownik był już zalogowany, ale nie ma praw dostępu do danego zasobu, do przeglądarki zostanie zwrócony komunikat 403 Forbidden.

<bean id="exceptionTranslationFilter" class="org.acegisecurity.ui.ExceptionTranslationFilter">
	<property name="authenticationEntryPoint">
		<ref bean="formLoginAuthenticationEntryPoint" />
	</property>
</bean>

FieldSecurityInterceptor

Bean zawierający informacje o zabezpieczonych zasobach. Ograniczenia dostępu definiujemy za pomocą ścieżek URL. Definiujemy je w objectDefinitionSource.

<bean id="filterSecurityInterceptor" class="org.acegisecurity.intercept.web.FilterSecurityInterceptor">
	<property name="authenticationManager">
		<ref bean="authenticationManager" />
	</property>
	<property name="accessDecisionManager">
		<ref bean="accessDecisionManager" />
	</property>
	<property name="objectDefinitionSource">
		<value>
			CONVERT_URL_TO_LOWERCASE_BEFORE_COMPARISON
			PATTERN_TYPE_APACHE_ANT
			/secure/admin/*=ROLE_ADMIN
			/secure/user/*=ROLE_USER
		</value>
	</property>
</bean>

W powyższym przykładzie widzimy zdefiniowane dwie ścieżki. Do każdej z nich została przypisana inna rola. Użytkownicy z posiadający dostęp do jednej z nich będą posiadali dostęp do jednej ścieżki.

AuthenticationManager

<bean id="authenticationManager" class="org.acegisecurity.providers.ProviderManager">
	<property name="providers">
		<list>
			<ref bean="daoAuthenticationProvider" />
		</list>
	</property>
</bean>

Jak widać konfiguracja samego managera zawiera jedynie źródło danych, potrzebnych do weryfikacji użytkownika. Źródłem danych może być JDBC lub LDAP. W tym przypadku pokażę jednak jak skorzystać z prostego źródła InMemoryDaoImpl. Pozwala ono definiować użytkowników w springowym xml’u. Poniżej konfiguracja:

<bean id="daoAuthenticationProvider" class="org.acegisecurity.providers.dao.DaoAuthenticationProvider">
	<property name="userDetailsService">
		<ref bean="userDetailsProvider" />
	</property>
</bean>
<bean id="userDetailsProvider" class="org.acegisecurity.userdetails.memory.InMemoryDaoImpl">
	<property name="userMap">
		<value>
			admin=acegi,ROLE_ADMIN
			user=security,ROLE_USER
			root=demo,ROLE_ADMIN,ROLE_USER
		</value>
	</property>
</bean>

Mamy tu zdefiniowanych trzech użytkowników, jeden z nich ma przypisane dwie role. Będzie on miał dostęp do zasobów przeznaczonych dla każdej z nich.

AccessDecisionManager

Komponent odpowiedzialny za ustalenie czy dany użytkownik ma prawo dostępu do danego zasobu. Do podjęcia decyzji używany jest RoleVoter.

<bean id="accessDecisionManager" class="org.acegisecurity.vote.UnanimousBased">
	<property name="decisionVoters">
		<list>
			<ref bean="roleVoter" />
		</list>
	</property>
</bean>
<bean id="roleVoter" class="org.acegisecurity.vote.RoleVoter">
	<property name="rolePrefix">
		<value>ROLE_</value>
	</property>
</bean>

AuthenticationEntryPoint

Element odpowiedzialny za zdefiniowanie formularza logowania. Za jego pomocą możemy również wymusić przesyłanie loginu i hasła za pomocą https, ustawiając property forceHttps na true.

<bean id="formLoginAuthenticationEntryPoint" class="org.acegisecurity.ui.webapp.AuthenticationProcessingFilterEntryPoint">
	<property name="loginFormUrl">
		<value>/login.jsp</value>
	</property>
</bean>

Ekran logowania

<form method="POST" action="<c:url value='j_acegi_security_check' />" >
	Username: <input type="text" name="j_username"><br>
	Password: <input type="password" name="j_password"><br>
	<input type="submit" >
</form>

Podsumowanie

Jak widać przygotowanie uwierzytelniania za pomocą Acegi nie jest szczególnie skomplikowane. Praktycznie cała konfiguracja jest zawarta w Springowych plikach XML i nie powinna sprawić nikomu kłopotów. Polecam korzystanie z Acegi przy aplikacjach o małych i średnich wymogach bezpieczeństwa. Jeśli korzystacie jednocześnie z SiteMesh upewnijcie się, że filtry Acegi wywoływane są jako pierwsze.

Podziel się z innymi:
  • Wykop
  • Digg
  • del.icio.us
  • StumbleUpon
  • Slashdot

5 Responses to “Acegi – Uwierzytelnianie i Autoryzacja w Springu”

  1. Mariusz Lipiński Says:

    “Polecam korzystanie z Acegi przy aplikacjach o małych i średnich wymogach bezpieczeństwa” – a co z aplikacjami o dużych wymaganiach jeśli chodzi o bezpieczeństwo? Acegi nie jest dla takich aplikacji odpowiedni? Jeśli nie Acegi to co? Przede wszystkim co to znaczy “duże wymagania”? Chodzi o elastyczność/usability czy o odporność na ataki?

  2. Michał Gołacki Says:

    Swojego czasu słyszałem opinię, że Acegi sprawdza się najlepiej na prostszych serwerach aplikacji, aby uzyskać możliwość lepszego dostosowania do wymogów bezpieczeństwa lepiej sprawdzi się bardziej zaawansowany serwer i korzystanie z jego systemu kontroli dostępu.

  3. ptr Says:

    A można prosić o trochę więcej szczegółów? Albo o uzasadnienie twierdzenia? Jaki bardziej zaawansowany serwer masz na myśli?

  4. space invader Says:

    Witam
    Zrobiłem applikację na podstawie tego przykładu SpringMVC, Velocity, konfigurację w dużej mierze oparłem na adnotacjach. Wszystko chula stronki są zabezpieczone. Mam pytanie jak zrobić aby po prawidłowym zalogowaniu stworzyć zmienną sesyjną np zawierającą login zalogowanego? Taki logi później bym wyświetlał na stronie.

  5. Michał Mally Says:

    Aby uzyskać dostęp do danych uwierzytelnionego użytkownika możesz skorzystać z następującej konstrukcji:
    SecurityContextHolder.getContext().getAuthentication().getPrincipal();

    Powyższe wywołanie przy w miarę standardowej konfiguracji (z tego co pamiętam) zwróci obiekt klasy org.springframework.security.userdetails.User.

Leave a Reply

Security Code: