Skip to content

Commit

Permalink
Merge pull request #59 from swedenconnect/feature/IS-54-session-conf
Browse files Browse the repository at this point in the history
Built-in session and audit configuration
  • Loading branch information
martin-lindstrom authored Apr 9, 2024
2 parents 3dca22c + f24a6d9 commit 1bc209b
Show file tree
Hide file tree
Showing 50 changed files with 2,829 additions and 70 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -35,4 +35,4 @@ See [https://docs.swedenconnect.se/saml-identity-provider](https://docs.swedenco

-----

Copyright © 2022-2023, [Myndigheten för digital förvaltning - Swedish Agency for Digital Government (DIGG)](http://www.digg.se). Licensed under version 2.0 of the [Apache License](http://www.apache.org/licenses/LICENSE-2.0).
Copyright © 2022-2024, [Myndigheten för digital förvaltning - Swedish Agency for Digital Government (DIGG)](http://www.digg.se). Licensed under version 2.0 of the [Apache License](http://www.apache.org/licenses/LICENSE-2.0).
22 changes: 21 additions & 1 deletion autoconfigure/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
<parent>
<groupId>se.swedenconnect.spring.saml.idp</groupId>
<artifactId>spring-saml-idp-parent</artifactId>
<version>2.0.2</version>
<version>2.1.0-SNAPSHOT</version>
</parent>

<name>Sweden Connect :: Spring SAML Identity Provider :: Spring Boot Autoconfigure module</name>
Expand Down Expand Up @@ -77,7 +77,27 @@
<artifactId>spring-saml-idp</artifactId>
<version>${project.version}</version>
</dependency>

<!-- Optional Redis support -->
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-redis</artifactId>
<optional>true</optional>
</dependency>

<dependency>
<groupId>org.springframework.session</groupId>
<artifactId>spring-session-data-redis</artifactId>
<optional>true</optional>
</dependency>

<dependency>
<groupId>org.redisson</groupId>
<artifactId>redisson-spring-boot-starter</artifactId>
<version>3.25.2</version>
<optional>true</optional>
</dependency>

</dependencies>

</project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
/*
* Copyright 2023-2024 Sweden Connect
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package se.swedenconnect.spring.saml.idp.autoconfigure.audit;

import java.util.function.Predicate;

import org.springframework.boot.actuate.audit.AuditEvent;
import org.springframework.boot.actuate.audit.AuditEventRepository;

import se.swedenconnect.spring.saml.idp.audit.repository.AuditEventMapper;

/**
* For creating Redis {@link AuditEventRepository} beans.
*/
@FunctionalInterface
public interface AuditEventRepositoryFactory {

/**
* Creates an {@link AuditEventRepository}.
*
* @param name the Redis name for the list/timeseries
* @param auditEventMapper the event mapper
* @param filter the filter predicate
* @return an {@link AuditEventRepository}
*/
AuditEventRepository create(
final String name, final AuditEventMapper auditEventMapper, Predicate<AuditEvent> filter);

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,152 @@
/*
* Copyright 2023-2024 Sweden Connect
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package se.swedenconnect.spring.saml.idp.autoconfigure.audit;

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import java.util.function.Predicate;

import org.springframework.beans.factory.BeanCreationException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.actuate.audit.AuditEvent;
import org.springframework.boot.actuate.audit.AuditEventRepository;
import org.springframework.boot.actuate.autoconfigure.audit.AuditAutoConfiguration;
import org.springframework.boot.autoconfigure.AutoConfiguration;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;

import com.fasterxml.jackson.databind.ObjectMapper;

import se.swedenconnect.spring.saml.idp.audit.repository.AuditEventMapper;
import se.swedenconnect.spring.saml.idp.audit.repository.DelegatingAuditEventRepository;
import se.swedenconnect.spring.saml.idp.audit.repository.FileBasedAuditEventRepository;
import se.swedenconnect.spring.saml.idp.audit.repository.FilteringAuditEventRepository;
import se.swedenconnect.spring.saml.idp.audit.repository.JsonAuditEventMapper;
import se.swedenconnect.spring.saml.idp.audit.repository.MemoryBasedAuditEventRepository;

/**
* Auto configuration for auditing support where an {@link AuditEventRepository} is created.
*
* @author Martin Lindström
*/
@ConditionalOnMissingBean(AuditEventRepository.class)
@AutoConfiguration(before = AuditAutoConfiguration.class)
@EnableConfigurationProperties(AuditRepositoryConfigurationProperties.class)
public class AuditRepositoryAutoConfiguration {

/** The audit properties. */
private final AuditRepositoryConfigurationProperties properties;

/** The JSON object mapper needed. */
private final ObjectMapper objectMapper;

/**
* Constructor.
*
* @param properties the audit properties
* @param objectMapper the JSON object mapper
*/
public AuditRepositoryAutoConfiguration(final AuditRepositoryConfigurationProperties properties, final ObjectMapper objectMapper) {
this.properties = Objects.requireNonNull(properties, "properties must not be null");
this.objectMapper = Objects.requireNonNull(objectMapper, "objectMapper must not be null");
}

/**
* Creates an {@link AuditEventMapper} bean.
*
* @return the {@link AuditEventMapper} bean
*/
@ConditionalOnMissingBean
@Bean
AuditEventMapper auditEventMapper() {
return new JsonAuditEventMapper(this.objectMapper);
}

/**
* Sets up an {@link AuditEventRepository} bean according to the configuration properties (unless such a bean has
* already been provided).
*
* @param auditEventMapper the event mapper
* @param redisFactory optional factory bean for creating Redis repositories
* @return an {@link AuditEventRepository} bean
* @throws IOException for errors setting up the file repository
*/
@Bean
AuditEventRepository auditEventRepository(final AuditEventMapper auditEventMapper,
@Autowired(required = false) final AuditEventRepositoryFactory redisFactory) throws IOException {

final List<AuditEventRepository> repositories = new ArrayList<>();
final Predicate<AuditEvent> filter = FilteringAuditEventRepository.inclusionExclusionPredicate(
this.properties.getIncludeEvents(), this.properties.getExcludeEvents());

if (this.properties.getFile() != null) {
repositories
.add(new FileBasedAuditEventRepository(this.properties.getFile().getLogFile(), auditEventMapper, filter));
}
if (redisFactory != null) {
repositories.add(redisFactory.create(this.properties.getRedis().getName(), auditEventMapper, filter));
}
if (this.properties.getInMemory() != null) {
repositories.add(new MemoryBasedAuditEventRepository(filter, this.properties.getInMemory().getCapacity()));
}

// The file repository does not support reads, so if this is the only repository, install an in-memory
// repository as well.
//
if (repositories.size() == 1 && this.properties.getFile() != null) {
repositories.add(0, new MemoryBasedAuditEventRepository(filter));
}

// Make sure we have at least one repository ...
//
if (repositories.isEmpty()) {
repositories.add(new MemoryBasedAuditEventRepository(filter));
}

return repositories.size() == 1 ? repositories.get(0) : new DelegatingAuditEventRepository(repositories);
}

/**
* Throws a {@link BeanCreationException} when the type is "timeseries" and Redisson is not available.
*
* @return never returns anything
* @throws BeanCreationException to signal that Redisson is required
*/
@ConditionalOnProperty(value = "saml.idp.audit.redis.type", havingValue = "timeseries", matchIfMissing = false)
@ConditionalOnMissingBean(type = "org.redisson.api.RedissonClient")
@Bean
AuditEventRepositoryFactory noRedisTimeseriesRepository() {
throw new BeanCreationException("saml.idp.audit.redis.type is set to 'timeseries', but Redisson is not available");
}

/**
* Throws a {@link BeanCreationException} when the type is "list" and Redis is not available.
*
* @return never returns anything
* @throws BeanCreationException to signal that Redis is required
*/
@ConditionalOnProperty(value = "saml.idp.audit.redis.type", havingValue = "list", matchIfMissing = false)
@ConditionalOnMissingBean(type = "org.springframework.data.redis.core.StringRedisTemplate")
@Bean
AuditEventRepositoryFactory noRedisListRepository() {
throw new BeanCreationException("saml.idp.audit.redis.type is set to 'list', but Redis is not available");
}

}
Loading

0 comments on commit 1bc209b

Please sign in to comment.