CAS – konfiguracja aplikacji klienta cz. 2

W poprzednim poście opisywałem konfigurację aplikacji dostawcy tożsamości. W tej części przejdziemy przez zagadnienia integracji CAS z naszą aplikacją za pomocą biblioteki Pac4J.

Zależności Maven

Pierwszym krokiem integracji jest dodanie do naszego projektu niezbędnych zależności. Jest to Pac4J oraz integracja wspomnianej biblioteki ze Spring MVC lub Spring Boot.

<dependency>
    <groupId>org.pac4j</groupId>
    <artifactId>pac4j-cas</artifactId>
    <version>${pac4j.version}</version>
</dependency>
<dependency>
    <groupId>org.pac4j</groupId>
    <artifactId>pac4j-http</artifactId>
    <version>${pac4j.version}</version>
</dependency>
<dependency>
    <groupId>org.pac4j</groupId>
    <artifactId>spring-webmvc-pac4j</artifactId>
    <version>${spring-webmvc-pac4j.version}</version>
</dependency>

Przykładowe wersje powyższych artefaktów:

<spring-webmvc-pac4j.version>1.0.1</spring-webmvc-pac4j.version>
<pac4j.version>1.8.1</pac4j.version>

Najnowsze wersje można sprawdzać na stronie mvnrepository.com

Konfiguracja biblioteki Pac4J

Konfiguracja biblioteki Pac4J polega na konfiguracji klienta serwera CAS tzn. CasClient oraz utworzeniu obiektu klasy konfiguracyjnej.

@Configuration
@PropertySource(value = {"classpath:application.properties"})
public class Pac4jConfig {

    @Value("${salt}")
    private String salt;

    @Inject
    Environment environment;

    @Bean
    public Config config() {

        final CasClient casClient = new CasClient();
        casClient.setCasLoginUrl(environment.getProperty("cas.login.page"));
        casClient.setCasProtocol(CasClient.CasProtocol.CAS20);
        casClient.setLogoutHandler(new CasSingleSignOutHandler());
        casClient.addAuthorizationGenerator(new RolesAuthorizationGenerator());

        final Clients clients = new Clients(environment.getProperty("pac4j.application.callback"), casClient);

        final Config config = new Config(clients);
        config.addAuthorizer("admin", new RequireAnyRoleAuthorizer("ROLE_ADMIN"));
        config.addAuthorizer("user", new RequireAnyRoleAuthorizer("ROLE_USER", "ROLE_ADMIN"));

        return config;
    }
}

Konfiguracja klienta wymaga określenia adresu serwera CAS, sposobu wylogowania oraz preferowanego protokołu komunikacji pomiędzy aplikacją a dostawcą tożsamości (w tym przypadku CAS20). W celu dostosowania procesu autentykacji do obsługi wielu ról (dla jednego użytkownika) przygotowałem również specjalną klasę, która jest odpowiedzialna za generowanie obiektu zalogowanego klienta. W otrzymanym od dostawcy tożsamości komunikacie role połączone są przecinkiem w polu o nazwie roles .

public class RolesAuthorizationGenerator <U extends CommonProfile> implements AuthorizationGenerator<U> {

    private String rolesAttributeName = "roles";
    private String id = "id";

    @Override
    public void generate(final U profile) {
        String rolesValue = (String) profile.getAttribute(rolesAttributeName);

        profile.addRoles(Arrays.asList(rolesValue.split(",")));
        profile.setId(profile.getAttribute(id));
    }
}

Klasa konfiguracyjna pozwala na dodanie odpowiedniej obsługi poszczególnych ról, jakie planujemy akceptować w naszej aplikacji. Na potrzeby przykładu wybrałem dwie podstawowe: ROLE_ADMIN, ROLE_USER.

Plik konfiguracyjny

W pliku Pac4JConfig.java zostały użyte wartości zapisane w pliku konfiguracyjnym application.properties . Specyfikują one poszczególne adresy oraz porty, które są wykorzystywane podczas procesów związanych z autoryzacją.

#Pac4j login and cas
cas.host=https://127.0.0.1:8443/cas
cas.login.page=${cas.host}/login

cas.login.url=${cas.login.page}?service=${pac4j.application.callback}?client_name=CasClient

pac4j.application.callback=${application.host}/callback
pac4j.application.logout=${cas.host}/logout?service=${application.host}

#Pac4j logout configuration
pac4j.applicationLogout.defaultUrl=${cas.host}/logout
pac4j.applicationLogout.logoutUrlPattern=.*

Konfiguracja zabezpieczeń

Następnym krokiem konfiguracji naszej aplikacji jest określenie jakie adresy będą dostępne dla poszczególnych ról. Robimy to poprzez dodanie nowych interceptorów znanych ze Springa:

@Configuration
@ComponentScan({ "org.pac4j.springframework.web"})
public class SecurityConfig extends WebMvcConfigurerAdapter {

    @Autowired
    private Config config;

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(new RequiresAuthenticationInterceptor(config, "CasClient", "user")).addPathPatterns(
                "/cas/*",
                "/app/*",
                "/api/*",
                "/user/management",
                "/user/management/*");
        registry.addInterceptor(
                new RequiresAuthenticationInterceptor(config, "CasClient", "admin")
        ).addPathPatterns("/admin/*");
    }
}

Jako 3 argument w konstruktorze klasy RequiresAuthenticationInterceptor  podajemy nazwy, które ustawiliśmy dla poszczególnych ról w pliku Pac4JConfig.java.

Podsumowanie

Dzięki bibliotece Pac4J oraz jej integracji z platformą Spring konfiguracja aplikacji w celu korzystania z CAS jako dostawcy tożsamości jest bardzo szybka. Warto dodać, że twórcy biblioteki przygotowali odpowiednie interfejsy do dostosowywania całego procesu autentykacji do naszych potrzeb.

Przydatne link

  1. Pac4J na github.com – github.com/pac4j/spring-security-pac4j
  2. Repozytorium Maven – mvnrepository.com/

You may also like

Comments