diff options
author | Fiete Ostkamp <Fiete.Ostkamp@telekom.de> | 2025-01-06 11:38:34 +0100 |
---|---|---|
committer | Fiete Ostkamp <fiete.ostkamp@telekom.de> | 2025-01-13 20:41:40 +0000 |
commit | 1733043036bbf8659db9856eaac583e70f44ed4a (patch) | |
tree | 057a884a61ba32e3bc4b4da1762c6ae6d459de28 | |
parent | dd4a7968d539a958b2ddccb77d00fcb68eb177b7 (diff) |
Make aai-resources agnostic of the embedded server (remove jetty-specific code)oslo
- small adjustments to authentication
- make users configurable via aai.basic-auth.users[] in application.properties
- remove Keycloak integration [0]
[0] for the following reasons:
- integration test (MultiTenancyTest) already not working
- dependency is ancient (uses 11, 26 is available as of writing)
- keycloak autoconfiguration is in conflict with spring security
- keycloak-specific starters have been deprecated and users are advised to
use the out-of-the-box spring OIDC integration [1]
- there is no (and likely never will be a) starter that is compatible with spring-boot 3
[1] https://www.keycloak.org/2023/03/adapter-deprecation-update
Issue-ID: AAI-4100
Change-Id: I8440f44106f9ba2cbd4addfa88efb63329365977
Signed-off-by: Fiete Ostkamp <Fiete.Ostkamp@telekom.de>
32 files changed, 345 insertions, 1246 deletions
@@ -2,8 +2,6 @@ .project target/ **/logs/ -bundleconfig-local/etc/auth/aai-client-cert.p12 -bundleconfig-local/etc/auth/tomcat_keystore bundleconfig-local/etc/logback.xml /.pydevproject /bin/ @@ -14,4 +12,4 @@ test_csvWriter.csv *.iml aai-resources/debug-logs/EELF/ .vscode -.classpath
\ No newline at end of file +.classpath diff --git a/aai-resources/.gitignore b/aai-resources/.gitignore index 47d0f721..9d979909 100644 --- a/aai-resources/.gitignore +++ b/aai-resources/.gitignore @@ -1,8 +1,6 @@ .settings target/ **/logs/ -bundleconfig-local/etc/auth/aai-client-cert.p12 -bundleconfig-local/etc/auth/tomcat_keystore bundleconfig-local/etc/oxm src/main/aai_schema bundleconfig-local/etc/logback.xml @@ -15,4 +13,4 @@ bundleconfig-local/etc/logback.xml **/dbedgerules/** **/oxm/** **/.classpath -.classpath
\ No newline at end of file +.classpath diff --git a/aai-resources/pom.xml b/aai-resources/pom.xml index d5dacd40..8910d5af 100644 --- a/aai-resources/pom.xml +++ b/aai-resources/pom.xml @@ -21,14 +21,14 @@ --> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" - xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>org.onap.aai.resources</groupId> <artifactId>aai-resources</artifactId> <parent> <groupId>org.onap.aai.resources</groupId> <artifactId>resources</artifactId> - <version>1.15.4-SNAPSHOT</version> + <version>1.15.5-SNAPSHOT</version> </parent> <properties> <java.version>11</java.version> @@ -81,9 +81,7 @@ <gremlin.version>3.5.8</gremlin.version> --> <javax.servlet.version>4.0.1</javax.servlet.version> - <keycloak.version>11.0.2</keycloak.version> - <testcontainers.version>1.20.4</testcontainers.version> - <testcontainers-keycloak.version>1.6.1</testcontainers-keycloak.version> + <testcontainers.version>1.19.8</testcontainers.version> <mockito.core.version>4.4.0</mockito.core.version> <eclipse.persistence.version>2.7.7</eclipse.persistence.version> <!-- Setting some default value to not complain by editor but it will be overridden by gmaven plugin --> @@ -107,15 +105,15 @@ <build> <plugins> <plugin> - <groupId>org.codehaus.groovy.maven</groupId> - <artifactId>gmaven-plugin</artifactId> - <version>1.0</version> - <executions> - <execution> - <phase>pre-clean</phase> - </execution> - </executions> - </plugin> + <groupId>org.codehaus.groovy.maven</groupId> + <artifactId>gmaven-plugin</artifactId> + <version>1.0</version> + <executions> + <execution> + <phase>pre-clean</phase> + </execution> + </executions> + </plugin> <plugin> <groupId>io.fabric8</groupId> <artifactId>docker-maven-plugin</artifactId> @@ -286,7 +284,7 @@ </dependency> <dependency> <groupId>org.springframework.boot</groupId> - <artifactId>spring-boot-starter-web</artifactId> + <artifactId>spring-boot-starter-jersey</artifactId> <exclusions> <exclusion> <groupId>org.springframework.boot</groupId> @@ -296,12 +294,25 @@ </dependency> <dependency> <groupId>org.springframework.boot</groupId> - <artifactId>spring-boot-starter-test</artifactId> - <scope>test</scope> + <artifactId>spring-boot-starter-jetty</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> - <artifactId>spring-boot-starter-jetty</artifactId> + <artifactId>spring-boot-starter-security</artifactId> + </dependency> + <dependency> + <groupId>org.springframework.boot</groupId> + <artifactId>spring-boot-starter-validation</artifactId> + </dependency> + <dependency> + <groupId>org.springframework.boot</groupId> + <artifactId>spring-boot-configuration-processor</artifactId> + <optional>true</optional> + </dependency> + <dependency> + <groupId>org.springframework.boot</groupId> + <artifactId>spring-boot-starter-test</artifactId> + <scope>test</scope> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> @@ -416,15 +427,15 @@ <version>6.6</version> </dependency> <dependency> - <groupId>org.hamcrest</groupId> - <artifactId>hamcrest</artifactId> - <version>2.2</version> - <exclusions> - <exclusion> - <groupId>junit</groupId> - <artifactId>junit</artifactId> - </exclusion> - </exclusions> + <groupId>org.hamcrest</groupId> + <artifactId>hamcrest</artifactId> + <version>2.2</version> + <exclusions> + <exclusion> + <groupId>junit</groupId> + <artifactId>junit</artifactId> + </exclusion> + </exclusions> </dependency> <dependency> <groupId>com.google.guava</groupId> @@ -441,9 +452,9 @@ <scope>test</scope> </dependency> <dependency> - <groupId>org.mockito</groupId> - <artifactId>mockito-junit-jupiter</artifactId> - <scope>test</scope> + <groupId>org.mockito</groupId> + <artifactId>mockito-junit-jupiter</artifactId> + <scope>test</scope> </dependency> <dependency> <groupId>com.beust</groupId> @@ -470,7 +481,7 @@ <dependency> <groupId>org.javatuples</groupId> <artifactId>javatuples</artifactId> - <scope>compile</scope> + <version>1.2</version> </dependency> <dependency> <groupId>com.google.code.gson</groupId> @@ -535,32 +546,6 @@ </exclusion> </exclusions> </dependency> - <!-- - Explicitly stating the security spring framework and - exclude the bouncy castle since that is somehow overwriting - our p12 file decryption that's built into java security - This will cause the password is incorrect - This needs to be added back if org.bouncy castle dependency - sneaks backs in and causing issues with the two way ssl - --> - <dependency> - <groupId>org.springframework.security</groupId> - <artifactId>spring-security-rsa</artifactId> - <exclusions> - <exclusion> - <groupId>org.bouncycastle</groupId> - <artifactId>bcpkix-jdk15on</artifactId> - </exclusion> - </exclusions> - </dependency> - <dependency> - <groupId>io.netty</groupId> - <artifactId>netty-handler</artifactId> - </dependency> - <dependency> - <groupId>io.netty</groupId> - <artifactId>netty-all</artifactId> - </dependency> <!-- Only used for the WebTestClient --> <dependency> @@ -589,28 +574,8 @@ <artifactId>gremlin-groovy</artifactId> </dependency> <dependency> - <groupId>org.springframework.boot</groupId> - <artifactId>spring-boot-starter-security</artifactId> - </dependency> - <dependency> - <groupId>org.keycloak</groupId> - <artifactId>keycloak-spring-boot-starter</artifactId> - </dependency> - <dependency> - <groupId>com.github.dasniko</groupId> - <artifactId>testcontainers-keycloak</artifactId> - <version>${testcontainers-keycloak.version}</version> - <scope>test</scope> - </dependency> - <dependency> - <groupId>org.junit.jupiter</groupId> - <artifactId>junit-jupiter</artifactId> - <scope>test</scope> - </dependency> - <dependency> - <groupId>org.keycloak</groupId> - <artifactId>keycloak-admin-client</artifactId> - <version>${keycloak.version}</version> + <groupId>org.junit.jupiter</groupId> + <artifactId>junit-jupiter</artifactId> <scope>test</scope> </dependency> <dependency> @@ -644,26 +609,19 @@ <scope>test</scope> </dependency> <dependency> - <groupId>org.projectlombok</groupId> - <artifactId>lombok</artifactId> - <version>1.18.34</version> - <scope>provided</scope> - </dependency> + <groupId>org.projectlombok</groupId> + <artifactId>lombok</artifactId> + <version>1.18.34</version> + <scope>provided</scope> + </dependency> <dependency> - <groupId>com.fasterxml.jackson.dataformat</groupId> - <artifactId>jackson-dataformat-xml</artifactId> - </dependency> + <groupId>com.fasterxml.jackson.dataformat</groupId> + <artifactId>jackson-dataformat-xml</artifactId> + </dependency> </dependencies> <dependencyManagement> <dependencies> <dependency> - <groupId>org.keycloak.bom</groupId> - <artifactId>keycloak-adapter-bom</artifactId> - <version>${keycloak.version}</version> - <type>pom</type> - <scope>import</scope> - </dependency> - <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-dependencies</artifactId> <version>${spring-cloud.version}</version> @@ -737,8 +695,6 @@ <resource> <directory>${project.basedir}/src/main/resources/etc/auth/</directory> <includes> - <include>aai-client-cert.p12</include> - <include>tomcat_keystore</include> <include>aai_policy.json</include> </includes> <targetPath>${project.build.directory}/swm/package/nix/dist_files/opt/app/${project.artifactId}/appconfig</targetPath> @@ -927,29 +883,29 @@ <artifactId>maven-deploy-plugin</artifactId> </plugin> <plugin> - <artifactId>maven-resources-plugin</artifactId> - <version>3.0.0</version> - <executions> - <execution> - <id>copy-fat-jar</id> - <phase>post-integration-test</phase> - <goals> - <goal>copy-resources</goal> - </goals> - <configuration> - <outputDirectory>${aai.build.directory}/lib/</outputDirectory> - <resources> - <resource> - <directory>${project.build.directory}/</directory> - <includes> - <include>${project.artifactId}-${project.version}.jar</include> - </includes> - <filtering>false</filtering> - </resource> - </resources> - </configuration> - </execution> - </executions> + <artifactId>maven-resources-plugin</artifactId> + <version>3.0.0</version> + <executions> + <execution> + <id>copy-fat-jar</id> + <phase>post-integration-test</phase> + <goals> + <goal>copy-resources</goal> + </goals> + <configuration> + <outputDirectory>${aai.build.directory}/lib/</outputDirectory> + <resources> + <resource> + <directory>${project.build.directory}/</directory> + <includes> + <include>${project.artifactId}-${project.version}.jar</include> + </includes> + <filtering>false</filtering> + </resource> + </resources> + </configuration> + </execution> + </executions> </plugin> <plugin> <groupId>org.springframework.boot</groupId> diff --git a/aai-resources/src/main/java/org/onap/aai/IncreaseNodesTool.java b/aai-resources/src/main/java/org/onap/aai/IncreaseNodesTool.java index 9331f2f5..68ed2fb6 100644 --- a/aai-resources/src/main/java/org/onap/aai/IncreaseNodesTool.java +++ b/aai-resources/src/main/java/org/onap/aai/IncreaseNodesTool.java @@ -41,7 +41,6 @@ import org.onap.aai.introspection.LoaderFactory; import org.onap.aai.introspection.ModelType; import org.onap.aai.introspection.exceptions.AAIUnknownObjectException; import org.onap.aai.logging.ErrorLogHelper; -import org.onap.aai.restclient.PropertyPasswordConfiguration; import org.onap.aai.serialization.db.EdgeSerializer; import org.onap.aai.serialization.engines.TransactionalGraphEngine; import org.onap.aai.setup.SchemaVersions; @@ -76,8 +75,6 @@ public class IncreaseNodesTool { throws AAIUnknownObjectException, UnsupportedEncodingException, AAIException { AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(); - PropertyPasswordConfiguration initializer = new PropertyPasswordConfiguration(); - initializer.initialize(context); try { context.scan("org.onap.aai.config", "org.onap.aai.setup"); context.refresh(); @@ -129,7 +126,7 @@ public class IncreaseNodesTool { * /cloud-infrastructure/pservers/pserver/ * /network/pnfs/pnf/ * /cloud-infrastructure/pservers/pserver/random-056fd6c4-7313-4fa0-b854-0d9983bdb0ab/p-interfaces/p-interface/ - * + * * @param * @param * @param cArgs diff --git a/aai-resources/src/main/java/org/onap/aai/ResourcesApp.java b/aai-resources/src/main/java/org/onap/aai/ResourcesApp.java index 51f5609f..7e1bd3a9 100644 --- a/aai-resources/src/main/java/org/onap/aai/ResourcesApp.java +++ b/aai-resources/src/main/java/org/onap/aai/ResourcesApp.java @@ -30,7 +30,6 @@ import org.onap.aai.dbmap.AAIGraph; import org.onap.aai.exceptions.AAIException; import org.onap.aai.logging.ErrorLogHelper; import org.onap.aai.nodes.NodeIngestor; -import org.onap.aai.restclient.PropertyPasswordConfiguration; import org.onap.aai.util.AAIConfig; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -42,9 +41,11 @@ import org.springframework.boot.autoconfigure.data.cassandra.CassandraDataAutoCo import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration; import org.springframework.boot.autoconfigure.jdbc.DataSourceTransactionManagerAutoConfiguration; import org.springframework.boot.autoconfigure.orm.jpa.HibernateJpaAutoConfiguration; +import org.springframework.boot.context.properties.EnableConfigurationProperties; import org.springframework.core.env.Environment; import org.springframework.core.env.Profiles; +@EnableConfigurationProperties @SpringBootApplication( exclude = {DataSourceAutoConfiguration.class, DataSourceTransactionManagerAutoConfiguration.class, HibernateJpaAutoConfiguration.class, CassandraDataAutoConfiguration.class, CassandraAutoConfiguration.class}) @@ -105,7 +106,6 @@ public class ResourcesApp { SpringApplication app = new SpringApplication(ResourcesApp.class); app.setLogStartupInfo(false); app.setRegisterShutdownHook(true); - app.addInitializers(new PropertyPasswordConfiguration()); env = app.run(args).getEnvironment(); } catch (Exception ex) { AAIException aai = null; @@ -132,8 +132,6 @@ public class ResourcesApp { logger.info("Resources MicroService Started"); logger.debug("Resources MicroService Started"); - System.out.println("Resources Microservice Started"); - } public static void setDefaultProps() { diff --git a/aai-resources/src/main/java/org/onap/aai/config/JettyPasswordDecoder.java b/aai-resources/src/main/java/org/onap/aai/config/AuthProperties.java index 833fd563..1ecffb6f 100644 --- a/aai-resources/src/main/java/org/onap/aai/config/JettyPasswordDecoder.java +++ b/aai-resources/src/main/java/org/onap/aai/config/AuthProperties.java @@ -2,7 +2,7 @@ * ============LICENSE_START======================================================= * org.onap.aai * ================================================================================ - * Copyright © 2017-2018 AT&T Intellectual Property. All rights reserved. + * Copyright © 2025 Deutsche Telekom. All rights reserved. * ================================================================================ * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -20,15 +20,28 @@ package org.onap.aai.config; -import org.eclipse.jetty.util.security.Password; +import java.util.List; -public class JettyPasswordDecoder implements PasswordDecoder { +import javax.validation.constraints.NotEmpty; - @Override - public String decode(String input) { - if (input.startsWith("OBF:")) { - return Password.deobfuscate(input); - } - return Password.deobfuscate("OBF:" + input); - } +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.context.annotation.Configuration; + +import lombok.Data; + +@Data +@Configuration +@ConfigurationProperties(prefix = "aai.basic-auth") +public class AuthProperties { + + boolean enabled = true; + + @NotEmpty + List<User> users; + + @Data + public static class User { + private String username; + private String password; + } } diff --git a/aai-resources/src/main/java/org/onap/aai/config/PasswordDecoder.java b/aai-resources/src/main/java/org/onap/aai/config/PasswordDecoder.java deleted file mode 100644 index 8ad75d9d..00000000 --- a/aai-resources/src/main/java/org/onap/aai/config/PasswordDecoder.java +++ /dev/null @@ -1,26 +0,0 @@ -/** - * ============LICENSE_START======================================================= - * org.onap.aai - * ================================================================================ - * Copyright © 2017-2018 AT&T Intellectual Property. All rights reserved. - * ================================================================================ - * 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. - * ============LICENSE_END========================================================= - */ - -package org.onap.aai.config; - -public interface PasswordDecoder { - - String decode(String input); -} diff --git a/aai-resources/src/main/java/org/onap/aai/config/PropertyPasswordConfiguration.java b/aai-resources/src/main/java/org/onap/aai/config/PropertyPasswordConfiguration.java deleted file mode 100644 index f205804f..00000000 --- a/aai-resources/src/main/java/org/onap/aai/config/PropertyPasswordConfiguration.java +++ /dev/null @@ -1,159 +0,0 @@ -/** - * ============LICENSE_START======================================================= - * org.onap.aai - * ================================================================================ - * Copyright © 2017-2018 AT&T Intellectual Property. All rights reserved. - * ================================================================================ - * 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. - * ============LICENSE_END========================================================= - */ - -package org.onap.aai.config; - -import java.io.File; -import java.io.FileInputStream; -import java.io.IOException; -import java.io.InputStream; -import java.nio.charset.Charset; -import java.util.LinkedHashMap; -import java.util.Map; -import java.util.Properties; -import java.util.regex.Matcher; -import java.util.regex.Pattern; - -import org.apache.commons.io.IOUtils; -import org.springframework.context.ApplicationContextInitializer; -import org.springframework.context.ConfigurableApplicationContext; -import org.springframework.core.env.ConfigurableEnvironment; -import org.springframework.core.env.EnumerablePropertySource; -import org.springframework.core.env.MapPropertySource; -import org.springframework.core.env.PropertySource; - -import lombok.extern.slf4j.Slf4j; - -@Slf4j -public class PropertyPasswordConfiguration implements ApplicationContextInitializer<ConfigurableApplicationContext> { - - private static final Pattern decodePasswordPattern = Pattern.compile("password\\((.*?)\\)"); - private PasswordDecoder passwordDecoder = new JettyPasswordDecoder(); - - @Override - public void initialize(ConfigurableApplicationContext applicationContext) { - ConfigurableEnvironment environment = applicationContext.getEnvironment(); - String certPath = environment.getProperty("server.certs.location"); - File passwordFile = null; - File passphrasesFile = null; - InputStream passwordStream = null; - InputStream passphrasesStream = null; - Map<String, Object> sslProps = new LinkedHashMap<>(); - - // Override the passwords from application.properties if we find AAF certman files - if (certPath != null) { - try { - passwordFile = new File(certPath + ".password"); - passwordStream = new FileInputStream(passwordFile); - - if (passwordStream != null) { - String keystorePassword = null; - - keystorePassword = IOUtils.toString(passwordStream, Charset.defaultCharset()); - if (keystorePassword != null) { - keystorePassword = keystorePassword.trim(); - } - sslProps.put("server.ssl.key-store-password", keystorePassword); - sslProps.put("schema.service.ssl.key-store-password", keystorePassword); - } else { - log.info("Not using AAF Certman password file"); - } - } catch (IOException e) { - log.warn("Not using AAF Certman password file, e=" + e.getMessage()); - } finally { - if (passwordStream != null) { - try { - passwordStream.close(); - } catch (Exception e) { - } - } - } - try { - passphrasesFile = new File(certPath + ".passphrases"); - passphrasesStream = new FileInputStream(passphrasesFile); - - if (passphrasesStream != null) { - String truststorePassword = null; - Properties passphrasesProps = new Properties(); - passphrasesProps.load(passphrasesStream); - truststorePassword = passphrasesProps.getProperty("cadi_truststore_password"); - if (truststorePassword != null) { - truststorePassword = truststorePassword.trim(); - } - sslProps.put("server.ssl.trust-store-password", truststorePassword); - sslProps.put("schema.service.ssl.trust-store-password", truststorePassword); - } else { - log.info("Not using AAF Certman passphrases file"); - } - } catch (IOException e) { - log.warn("Not using AAF Certman passphrases file, e=" + e.getMessage()); - } finally { - if (passphrasesStream != null) { - try { - passphrasesStream.close(); - } catch (Exception e) { - } - } - } - } - for (PropertySource<?> propertySource : environment.getPropertySources()) { - Map<String, Object> propertyOverrides = new LinkedHashMap<>(); - decodePasswords(propertySource, propertyOverrides); - if (!propertyOverrides.isEmpty()) { - PropertySource<?> decodedProperties = - new MapPropertySource("decoded " + propertySource.getName(), propertyOverrides); - environment.getPropertySources().addBefore(propertySource.getName(), decodedProperties); - } - - } - if (!sslProps.isEmpty()) { - log.info("Using AAF Certman files"); - PropertySource<?> additionalProperties = new MapPropertySource("additionalProperties", sslProps); - environment.getPropertySources().addFirst(additionalProperties); - } - } - - private void decodePasswords(PropertySource<?> source, Map<String, Object> propertyOverrides) { - if (source instanceof EnumerablePropertySource) { - EnumerablePropertySource<?> enumerablePropertySource = (EnumerablePropertySource<?>) source; - for (String key : enumerablePropertySource.getPropertyNames()) { - Object rawValue = source.getProperty(key); - if (rawValue instanceof String) { - String decodedValue = decodePasswordsInString((String) rawValue); - propertyOverrides.put(key, decodedValue); - } - } - } - } - - private String decodePasswordsInString(String input) { - if (input == null) - return null; - StringBuffer output = new StringBuffer(); - Matcher matcher = decodePasswordPattern.matcher(input); - while (matcher.find()) { - String replacement = passwordDecoder.decode(matcher.group(1)); - matcher.appendReplacement(output, replacement); - } - matcher.appendTail(output); - return output.toString(); - } - -} diff --git a/aai-resources/src/main/java/org/onap/aai/interceptors/pre/AuthInterceptor.java b/aai-resources/src/main/java/org/onap/aai/interceptors/pre/AuthInterceptor.java new file mode 100644 index 00000000..e590d9f6 --- /dev/null +++ b/aai-resources/src/main/java/org/onap/aai/interceptors/pre/AuthInterceptor.java @@ -0,0 +1,87 @@ +/** + * ============LICENSE_START======================================================= + * org.onap.aai + * ================================================================================ + * Copyright © 2025 Deutsche Telekom. All rights reserved. + * ================================================================================ + * 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. + * ============LICENSE_END========================================================= + */ + +package org.onap.aai.interceptors.pre; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; +import java.util.Optional; +import java.util.regex.Pattern; + +import javax.annotation.Priority; +import javax.ws.rs.container.ContainerRequestContext; +import javax.ws.rs.container.ContainerRequestFilter; +import javax.ws.rs.container.PreMatching; +import javax.ws.rs.core.MediaType; +import javax.ws.rs.core.Response; + +import org.onap.aai.ResourcesProfiles; +import org.onap.aai.exceptions.AAIException; +import org.onap.aai.interceptors.AAIContainerFilter; +import org.onap.aai.logging.ErrorLogHelper; +import org.onap.aai.service.AuthorizationService; +import org.springframework.context.annotation.Profile; +import org.springframework.stereotype.Component; + +import lombok.RequiredArgsConstructor; + +@Component +@PreMatching +@RequiredArgsConstructor +@Profile(ResourcesProfiles.ONE_WAY_SSL) // this mainly serves the purpose of making the tests work +@Priority(AAIRequestFilterPriority.AUTHORIZATION) +public class AuthInterceptor extends AAIContainerFilter implements ContainerRequestFilter { + + private static final Pattern PATTERN_ECHO = Pattern.compile("^.*/util/echo$"); + private static final Pattern PATTERN_ACTUATOR = Pattern.compile("^.*/actuator/.*$"); + private static final AAIException AAI_EXCEPTION = new AAIException("AAI_3300"); + private final AuthorizationService authorizationService; + + @Override + public void filter(ContainerRequestContext requestContext) throws IOException { + String path = requestContext.getUriInfo().getRequestUri().getPath(); + if (PATTERN_ECHO.matcher(path).matches() || PATTERN_ACTUATOR.matcher(path).matches()) { + return; + } + + String basicAuth = requestContext.getHeaders().getFirst("Authorization"); + if (basicAuth == null || !basicAuth.startsWith("Basic ")) { + Response errorResponse = errorResponse("AAI_3300", requestContext.getAcceptableMediaTypes()); + requestContext.abortWith(errorResponse); + return; + } + + if (!authorizationService.isAuthorized(basicAuth)) { + Response errorResponse = errorResponse("AAI_3300", requestContext.getAcceptableMediaTypes()); + requestContext.abortWith(errorResponse); + return; + } + } + + private Response errorResponse(String errorCode, List<MediaType> acceptHeaderValues) { + + return Response + .status(AAI_EXCEPTION.getErrorObject().getHTTPResponseCode()) + .entity(ErrorLogHelper.getRESTAPIErrorResponse(acceptHeaderValues, AAI_EXCEPTION, new ArrayList<>())) + .build(); + } + +} diff --git a/aai-resources/src/main/java/org/onap/aai/interceptors/pre/NamespaceInterceptor.java b/aai-resources/src/main/java/org/onap/aai/interceptors/pre/NamespaceInterceptor.java index c97e475a..7889a2c9 100644 --- a/aai-resources/src/main/java/org/onap/aai/interceptors/pre/NamespaceInterceptor.java +++ b/aai-resources/src/main/java/org/onap/aai/interceptors/pre/NamespaceInterceptor.java @@ -41,7 +41,6 @@ import javax.xml.transform.Source; import javax.xml.transform.stream.StreamResult; import javax.xml.transform.stream.StreamSource; -import org.onap.aai.IncreaseNodesTool; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; @@ -67,7 +66,7 @@ import org.xml.sax.InputSource; @ConditionalOnProperty(value = "aai.remove-xmlns.enabled", havingValue = "true", matchIfMissing = true) public class NamespaceInterceptor implements ReaderInterceptor { - private static final Logger log = LoggerFactory.getLogger(IncreaseNodesTool.class); + private static final Logger log = LoggerFactory.getLogger(NamespaceInterceptor.class); private static final String xslStr = String.join("\n", "<xsl:transform xmlns:xsl=\"http://www.w3.org/1999/XSL/Transform\" version=\"1.0\">", "<xsl:output version=\"1.0\" encoding=\"UTF-8\" indent=\"no\"/>", diff --git a/aai-resources/src/main/java/org/onap/aai/interceptors/pre/OneWaySslAuthorization.java b/aai-resources/src/main/java/org/onap/aai/interceptors/pre/OneWaySslAuthorization.java deleted file mode 100644 index b5321052..00000000 --- a/aai-resources/src/main/java/org/onap/aai/interceptors/pre/OneWaySslAuthorization.java +++ /dev/null @@ -1,83 +0,0 @@ -/** - * ============LICENSE_START======================================================= - * org.onap.aai - * ================================================================================ - * Copyright © 2017-2018 AT&T Intellectual Property. All rights reserved. - * ================================================================================ - * 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. - * ============LICENSE_END========================================================= - */ - -package org.onap.aai.interceptors.pre; - -import java.io.IOException; -import java.util.ArrayList; -import java.util.List; -import java.util.Optional; - -import javax.annotation.Priority; -import javax.ws.rs.container.ContainerRequestContext; -import javax.ws.rs.container.ContainerRequestFilter; -import javax.ws.rs.container.PreMatching; -import javax.ws.rs.core.MediaType; -import javax.ws.rs.core.Response; - -import org.onap.aai.ResourcesProfiles; -import org.onap.aai.exceptions.AAIException; -import org.onap.aai.interceptors.AAIContainerFilter; -import org.onap.aai.logging.ErrorLogHelper; -import org.onap.aai.service.AuthorizationService; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.context.annotation.Profile; - -@Profile(ResourcesProfiles.ONE_WAY_SSL) -@PreMatching -@Priority(AAIRequestFilterPriority.AUTHORIZATION) -public class OneWaySslAuthorization extends AAIContainerFilter implements ContainerRequestFilter { - - @Autowired - private AuthorizationService authorizationService; - - @Override - public void filter(ContainerRequestContext containerRequestContext) throws IOException { - - if (containerRequestContext.getUriInfo().getRequestUri().getPath().matches("^.*/util/echo$")) { - return; - } - - String basicAuth = containerRequestContext.getHeaderString("Authorization"); - List<MediaType> acceptHeaderValues = containerRequestContext.getAcceptableMediaTypes(); - - if (basicAuth == null || !basicAuth.startsWith("Basic ")) { - Optional<Response> responseOptional = errorResponse("AAI_3300", acceptHeaderValues); - containerRequestContext.abortWith(responseOptional.get()); - return; - } - - basicAuth = basicAuth.replaceAll("Basic ", ""); - - if (!authorizationService.checkIfUserAuthorized(basicAuth)) { - Optional<Response> responseOptional = errorResponse("AAI_3300", acceptHeaderValues); - containerRequestContext.abortWith(responseOptional.get()); - return; - } - - } - - private Optional<Response> errorResponse(String errorCode, List<MediaType> acceptHeaderValues) { - AAIException aaie = new AAIException(errorCode); - return Optional.of(Response.status(aaie.getErrorObject().getHTTPResponseCode()) - .entity(ErrorLogHelper.getRESTAPIErrorResponse(acceptHeaderValues, aaie, new ArrayList<>())).build()); - - } -} diff --git a/aai-resources/src/main/java/org/onap/aai/rest/ResourcesController.java b/aai-resources/src/main/java/org/onap/aai/rest/ResourcesController.java index 12839d48..1f66697e 100644 --- a/aai-resources/src/main/java/org/onap/aai/rest/ResourcesController.java +++ b/aai-resources/src/main/java/org/onap/aai/rest/ResourcesController.java @@ -34,8 +34,6 @@ import javax.ws.rs.core.*; import javax.ws.rs.core.Response.Status; import org.apache.commons.lang3.ObjectUtils; -import org.keycloak.adapters.springsecurity.account.SimpleKeycloakAccount; -import org.keycloak.adapters.springsecurity.token.KeycloakAuthenticationToken; import org.onap.aai.concurrent.AaiCallable; import org.onap.aai.introspection.Introspector; import org.onap.aai.introspection.sideeffect.OwnerCheck; @@ -65,7 +63,7 @@ public class ResourcesController extends RESTAPI { @Context HttpHeaders headers, @Context UriInfo info, @Context HttpServletRequest req) { - Set<String> roles = getRoles(req.getUserPrincipal(), req.getMethod()); + Set<String> roles = Collections.emptySet(); MediaType mediaType = headers.getMediaType(); return resourcesService.handleWrites(mediaType, HttpMethod.PUT, content, versionParam, uri, headers, info, roles); } @@ -96,7 +94,7 @@ public class ResourcesController extends RESTAPI { @Context HttpHeaders headers, @Context UriInfo info, @Context HttpServletRequest req) { - Set<String> roles = getRoles(req.getUserPrincipal(), req.getMethod()); + Set<String> roles = Collections.emptySet(); MediaType mediaType = MediaType.APPLICATION_JSON_TYPE; return resourcesService.handleWrites(mediaType, HttpMethod.MERGE_PATCH, content, versionParam, uri, headers, info, roles); @@ -134,7 +132,7 @@ public class ResourcesController extends RESTAPI { @Context HttpHeaders headers, @Context UriInfo info, @Context HttpServletRequest req) { - Set<String> roles = getRoles(req.getUserPrincipal(), req.getMethod()); + Set<String> roles = Collections.emptySet(); Pageable pageable = includeTotalCount == false ? new Pageable(resultIndex -1, resultSize) : new Pageable(resultIndex -1, resultSize).includeTotalCount(); @@ -159,7 +157,7 @@ public class ResourcesController extends RESTAPI { @Context UriInfo info, @QueryParam("resource-version") String resourceVersion, @Context HttpServletRequest req) { - Set<String> roles = getRoles(req.getUserPrincipal(), req.getMethod()); + Set<String> roles = Collections.emptySet(); return resourcesService.delete(versionParam, uri, headers, info, req, roles); } @@ -210,29 +208,4 @@ public class ResourcesController extends RESTAPI { protected boolean isEmptyObject(Introspector obj) { return "{}".equals(obj.marshal(false)); } - - private Set<String> getRoles(Principal userPrincipal, String method) { - KeycloakAuthenticationToken token = (KeycloakAuthenticationToken) userPrincipal; - if (ObjectUtils.isEmpty(token)) { - return Collections.emptySet(); - } - SimpleKeycloakAccount account = (SimpleKeycloakAccount) token.getDetails(); - if (ObjectUtils.isEmpty(account)) { - return Collections.emptySet(); - } - // When the request is not a GET, we need to exclude ReadOnly access roles - if (isNotGetRequest(method)) { - return getExcludedReadOnlyAccessRoles(account); - } - return account.getRoles(); - } - - private Set<String> getExcludedReadOnlyAccessRoles(SimpleKeycloakAccount account) { - return account.getRoles().stream().filter(role -> !role.endsWith(OwnerCheck.READ_ONLY_SUFFIX)) - .collect(Collectors.toSet()); - } - - private boolean isNotGetRequest(String method) { - return !Action.GET.name().equalsIgnoreCase(method); - } } diff --git a/aai-resources/src/main/java/org/onap/aai/rest/security/WebSecurityConfig.java b/aai-resources/src/main/java/org/onap/aai/rest/security/WebSecurityConfig.java deleted file mode 100644 index c63a70a0..00000000 --- a/aai-resources/src/main/java/org/onap/aai/rest/security/WebSecurityConfig.java +++ /dev/null @@ -1,79 +0,0 @@ -/** - * ============LICENSE_START======================================================= - * org.onap.aai - * ================================================================================ - * Copyright (C) 2019 Nordix Foundation. - * Modifications Copyright (C) 2019 AT&T Intellectual Property. - * Modifications Copyright (C) 2020 Bell Canada. - * ================================================================================ - * 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. - * - * SPDX-License-Identifier: Apache-2.0 - * ============LICENSE_END========================================================= - */ - -package org.onap.aai.rest.security; - -import org.keycloak.adapters.springboot.KeycloakSpringBootConfigResolver; -import org.keycloak.adapters.springsecurity.KeycloakConfiguration; -import org.keycloak.adapters.springsecurity.authentication.KeycloakAuthenticationProvider; -import org.keycloak.adapters.springsecurity.config.KeycloakWebSecurityConfigurerAdapter; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.web.servlet.ServletListenerRegistrationBean; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Import; -import org.springframework.context.annotation.Profile; -import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder; -import org.springframework.security.config.annotation.web.builders.HttpSecurity; -import org.springframework.security.config.annotation.web.builders.WebSecurity; -import org.springframework.security.core.authority.mapping.SimpleAuthorityMapper; -import org.springframework.security.core.session.SessionRegistryImpl; -import org.springframework.security.web.authentication.session.RegisterSessionAuthenticationStrategy; -import org.springframework.security.web.authentication.session.SessionAuthenticationStrategy; -import org.springframework.security.web.session.HttpSessionEventPublisher; - -@Profile("keycloak") -@KeycloakConfiguration -@Import({KeycloakSpringBootConfigResolver.class}) -public class WebSecurityConfig extends KeycloakWebSecurityConfigurerAdapter { - - @Autowired - public void configureGlobal(AuthenticationManagerBuilder auth) { - KeycloakAuthenticationProvider keycloakAuthenticationProvider = keycloakAuthenticationProvider(); - keycloakAuthenticationProvider.setGrantedAuthoritiesMapper(new SimpleAuthorityMapper()); - auth.authenticationProvider(keycloakAuthenticationProvider); - } - - @Bean - public ServletListenerRegistrationBean<HttpSessionEventPublisher> httpSessionEventPublisher() { - return new ServletListenerRegistrationBean<>(new HttpSessionEventPublisher()); - } - - @Bean - @Override - protected SessionAuthenticationStrategy sessionAuthenticationStrategy() { - return new RegisterSessionAuthenticationStrategy(new SessionRegistryImpl()); - } - - @Override - protected void configure(HttpSecurity http) throws Exception { - super.configure(http); - http.authorizeRequests().antMatchers("/**").permitAll().and().csrf().disable(); - } - - @Override - public void configure(WebSecurity web) { - web.ignoring().regexMatchers("^.*/util/echo$"); - } - -} diff --git a/aai-resources/src/main/java/org/onap/aai/service/AuthorizationService.java b/aai-resources/src/main/java/org/onap/aai/service/AuthorizationService.java index 0c219a75..7b420b9d 100644 --- a/aai-resources/src/main/java/org/onap/aai/service/AuthorizationService.java +++ b/aai-resources/src/main/java/org/onap/aai/service/AuthorizationService.java @@ -2,7 +2,7 @@ * ============LICENSE_START======================================================= * org.onap.aai * ================================================================================ - * Copyright © 2017-2018 AT&T Intellectual Property. All rights reserved. + * Copyright © 2025 Deutsche Telekom. All rights reserved. * ================================================================================ * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -20,92 +20,45 @@ package org.onap.aai.service; -import java.io.IOException; -import java.io.UnsupportedEncodingException; -import java.nio.file.Files; -import java.nio.file.Path; import java.util.Base64; -import java.util.HashMap; -import java.util.Map; -import java.util.stream.Stream; +import java.util.Set; +import java.util.stream.Collectors; -import javax.annotation.PostConstruct; - -import org.eclipse.jetty.util.security.Password; -import org.onap.aai.ResourcesProfiles; -import org.onap.aai.util.AAIConstants; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.context.annotation.Profile; +import org.onap.aai.config.AuthProperties; import org.springframework.stereotype.Service; -@Profile(ResourcesProfiles.ONE_WAY_SSL) +/** + * Should be removed once Spring Security-based auth works + */ @Service public class AuthorizationService { - private static final Logger logger = LoggerFactory.getLogger(AuthorizationService.class); - - private final Map<String, String> authorizedUsers = new HashMap<>(); - - private static final Base64.Encoder ENCODER = Base64.getEncoder(); - - @PostConstruct - public void init() { - - String basicAuthFile = getBasicAuthFilePath(); - - try (Stream<String> stream = Files.lines(Path.of(basicAuthFile))) { - stream.filter(line -> !line.startsWith("#")).forEach(str -> { - byte[] bytes = null; - - String usernamePassword = null; - String accessType = null; - - try { - String[] userAccessType = str.split(","); - - if (userAccessType == null || userAccessType.length != 2) { - throw new RuntimeException( - "Please check the realm.properties file as it is not conforming to the basic auth"); - } - - usernamePassword = userAccessType[0]; - accessType = userAccessType[1]; - - String[] usernamePasswordArray = usernamePassword.split(":"); - - if (usernamePasswordArray == null || usernamePasswordArray.length != 3) { - throw new RuntimeException("This username / pwd is not a valid entry in realm.properties"); - } - - String username = usernamePasswordArray[0]; - String password = null; - - if (str.contains("OBF:")) { - password = usernamePasswordArray[1] + ":" + usernamePasswordArray[2]; - password = Password.deobfuscate(password); - } - - bytes = ENCODER.encode((username + ":" + password).getBytes("UTF-8")); - - authorizedUsers.put(new String(bytes), accessType); - - } catch (UnsupportedEncodingException e) { - logger.error("Unable to support the encoding of the file" + basicAuthFile); - } - - authorizedUsers.put(new String(ENCODER.encode(bytes)), accessType); - }); - } catch (IOException e) { - logger.error("IO Exception occurred during the reading of realm.properties", e); - } - } + // Saved in this format for best performance + private final Set<String> authorizedHeaders; + + public AuthorizationService(AuthProperties authProperties) { + authorizedHeaders = getAuthorizedHeaders(authProperties); + } + + public boolean isAuthorized(String authHeaderValue) { + return authorizedHeaders.contains(authHeaderValue); + } + + /** + * Returns valid Bearer auth headers for all users. + * @param authProperties + * @param encoder + * @return + */ + private Set<String> getAuthorizedHeaders(AuthProperties authProperties) { + Base64.Encoder encoder = Base64.getEncoder(); + return authProperties.getUsers().stream() + .map(user -> user.getUsername() + ":" + user.getPassword()) + .map(usernamePasswordPair -> encoder.encode(usernamePasswordPair.getBytes())) + .map(String::new) + .map(encodedPair -> "Basic " + encodedPair) + .collect(Collectors.toSet()); + } - public boolean checkIfUserAuthorized(String authorization) { - return authorizedUsers.containsKey(authorization) && "admin".equals(authorizedUsers.get(authorization)); - } - public String getBasicAuthFilePath() { - return AAIConstants.AAI_HOME_ETC_AUTH + AAIConstants.AAI_FILESEP + "realm.properties"; - } } diff --git a/aai-resources/src/main/resources/application-keycloak.properties b/aai-resources/src/main/resources/application-keycloak.properties deleted file mode 100644 index d398256f..00000000 --- a/aai-resources/src/main/resources/application-keycloak.properties +++ /dev/null @@ -1,14 +0,0 @@ - -spring.autoconfigure.exclude=\ - org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration,\ - org.springframework.boot.autoconfigure.orm.jpa.HibernateJpaAutoConfiguration - -multi.tenancy.enabled=true -keycloak.auth-server-url=http://localhost:8180/auth -keycloak.realm=aai-resources -keycloak.resource=aai-resources-app -keycloak.public-client=true -keycloak.principal-attribute=preferred_username - -keycloak.ssl-required=external -keycloak.bearer-only=true
\ No newline at end of file diff --git a/aai-resources/src/main/resources/application.properties b/aai-resources/src/main/resources/application.properties index f0ef368a..c0c805fc 100644 --- a/aai-resources/src/main/resources/application.properties +++ b/aai-resources/src/main/resources/application.properties @@ -20,7 +20,6 @@ server.servlet.context-path=/ spring.autoconfigure.exclude=\ org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration,\ org.springframework.boot.autoconfigure.orm.jpa.HibernateJpaAutoConfiguration,\ - org.keycloak.adapters.springboot.KeycloakAutoConfiguration,\ org.springframework.boot.autoconfigure.security.servlet.SecurityAutoConfiguration,\ org.springframework.boot.actuate.autoconfigure.security.servlet.ManagementWebSecurityAutoConfiguration @@ -37,21 +36,8 @@ server.tomcat.max-idle-time=60000 # If you get an application startup failure that the port is already taken # If thats not it, please check if the key-store file path makes sense server.local.startpath=src/main/resources -server.basic.auth.location=${server.local.startpath}/etc/auth/realm.properties -server.certs.location=${server.local.startpath}/etc/auth/ -#server.keystore.name=keystore.jks -server.keystore.name=aai_keystore -server.truststore.name=aai_keystore -server.port=8447 -server.ssl.enabled=false -server.ssl.enabled-protocols=TLSv1.1,TLSv1.2 -server.ssl.key-store=${server.certs.location}${server.keystore.name} -server.ssl.key-store-password=password(OBF:1vn21ugu1saj1v9i1v941sar1ugw1vo0) -server.ssl.trust-store=${server.certs.location}${server.truststore.name} -server.ssl.trust-store-password=password(OBF:1vn21ugu1saj1v9i1v941sar1ugw1vo0) -server.ssl.client-auth=want -server.ssl.key-store-type=JKS +server.port=8447 null.db.serialization.enabled=true @@ -103,10 +89,6 @@ schema.service.nodes.endpoint=nodes?version= schema.service.edges.endpoint=edgerules?version= schema.service.versions.endpoint=versions -schema.service.ssl.key-store=${server.certs.location}${server.keystore.name} -schema.service.ssl.trust-store=${server.certs.location}${server.truststore.name} -schema.service.ssl.key-store-password=password(OBF:1vn21ugu1saj1v9i1v941sar1ugw1vo0) -schema.service.ssl.trust-store-password=password(OBF:1vn21ugu1saj1v9i1v941sar1ugw1vo0) schema.service.versions.override=false #To Expose the Prometheus scraping endpoint @@ -134,14 +116,6 @@ delta.events.enabled=false validation.service.client=one-way-ssl # Base url for the validation service validation.service.base.url=https://localhost:9501/services/validation-service -# Client certificate to use to make the request to validation -validation.service.ssl.key-store=${server.local.startpath}/etc/auth/aai-client-cert.p12 -# Truststore to use to make the request to validation -validation.service.ssl.trust-store=${server.local.startpath}/etc/auth/tomcat_keystore -# Client certificate password for the validation -validation.service.ssl.key-store-password=password(OBF:1vn21ugu1saj1v9i1v941sar1ugw1vo0) -# Truststore password for the validation -validation.service.ssl.trust-store-password=password(OBF:1vn21ugu1saj1v9i1v941sar1ugw1vo0) # Amount of time that the client should wait in milliseconds before request failing validation.service.timeout-in-milliseconds=3000 # List of aai node types that should be send to the validation microservice @@ -163,3 +137,7 @@ aai.actuator.echo.enabled=false aai.notifications.enabled=false aai.graph.properties.path=${server.local.startpath}/etc/appprops/janusgraph-realtime.properties + +aai.basic-auth.enabled=true +aai.basic-auth.users[0].username=AAI +aai.basic-auth.users[0].password=AAI diff --git a/aai-resources/src/main/resources/etc/appprops/aaiconfig.properties b/aai-resources/src/main/resources/etc/appprops/aaiconfig.properties index ecbbcb1c..cd197341 100644 --- a/aai-resources/src/main/resources/etc/appprops/aaiconfig.properties +++ b/aai-resources/src/main/resources/etc/appprops/aaiconfig.properties @@ -48,11 +48,6 @@ aai.server.url.base=https://localhost:8443/aai/ aai.server.url=https://localhost:8443/aai/v20/ aai.global.callback.url=https://localhost:8443/aai/ -aai.truststore.filename=aai_keystore -aai.truststore.passwd.x=OBF:1vn21ugu1saj1v9i1v941sar1ugw1vo0 -aai.keystore.filename=aai-client-cert.p12 -aai.keystore.passwd.x= - aai.notification.current.version=v20 aai.notificationEvent.default.status=UNPROCESSED aai.notificationEvent.default.eventType=AAI-EVENT diff --git a/aai-resources/src/test/java/org/onap/aai/ResourcesTestConfiguration.java b/aai-resources/src/test/java/org/onap/aai/ResourcesTestConfiguration.java index 93b15192..0d7ff7ef 100644 --- a/aai-resources/src/test/java/org/onap/aai/ResourcesTestConfiguration.java +++ b/aai-resources/src/test/java/org/onap/aai/ResourcesTestConfiguration.java @@ -24,7 +24,6 @@ import java.io.File; import java.io.FileInputStream; import java.io.IOException; import java.io.InputStream; -import java.security.KeyStore; import javax.net.ssl.SSLContext; @@ -63,20 +62,7 @@ public class ResourcesTestConfiguration { RestTemplate restTemplate = null; if (env.acceptsProfiles(Profiles.of(ResourcesProfiles.TWO_WAY_SSL, ResourcesProfiles.ONE_WAY_SSL))) { - char[] trustStorePassword = env.getProperty("server.ssl.trust-store-password").toCharArray(); - char[] keyStorePassword = env.getProperty("server.ssl.key-store-password").toCharArray(); - - String keyStore = env.getProperty("server.ssl.key-store"); - String trustStore = env.getProperty("server.ssl.trust-store"); - SSLContextBuilder sslContextBuilder = SSLContextBuilder.create(); - - if (env.acceptsProfiles(Profiles.of(ResourcesProfiles.TWO_WAY_SSL))) { - sslContextBuilder = - sslContextBuilder.loadKeyMaterial(loadPfx(keyStore, keyStorePassword), keyStorePassword); - } - - SSLContext sslContext = - sslContextBuilder.loadTrustMaterial(ResourceUtils.getFile(trustStore), trustStorePassword).build(); + SSLContext sslContext = SSLContextBuilder.create().build(); HttpClient client = HttpClients.custom().setSSLContext(sslContext) .setSSLHostnameVerifier((s, sslSession) -> true).build(); @@ -113,13 +99,4 @@ public class ResourcesTestConfiguration { return restTemplate; } - - private KeyStore loadPfx(String file, char[] password) throws Exception { - KeyStore keyStore = KeyStore.getInstance("PKCS12"); - File key = ResourceUtils.getFile(file); - try (InputStream in = new FileInputStream(key)) { - keyStore.load(in, password); - } - return keyStore; - } } diff --git a/aai-resources/src/test/java/org/onap/aai/config/WebClientConfiguration.java b/aai-resources/src/test/java/org/onap/aai/config/WebClientConfiguration.java index e412dede..e317ef0d 100644 --- a/aai-resources/src/test/java/org/onap/aai/config/WebClientConfiguration.java +++ b/aai-resources/src/test/java/org/onap/aai/config/WebClientConfiguration.java @@ -1,3 +1,23 @@ +/** + * ============LICENSE_START======================================================= + * org.onap.aai + * ================================================================================ + * Copyright © 2025 Deutsche Telekom. All rights reserved. + * ================================================================================ + * 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. + * ============LICENSE_END========================================================= + */ + package org.onap.aai.config; import java.time.Duration; @@ -7,7 +27,7 @@ import org.onap.aai.setup.SchemaVersions; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; import org.springframework.boot.test.context.TestConfiguration; -import org.springframework.boot.web.server.LocalServerPort; +import org.springframework.boot.test.web.server.LocalServerPort; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Lazy; import org.springframework.context.annotation.Primary; diff --git a/aai-resources/src/test/java/org/onap/aai/it/multitenancy/KeycloakTestConfiguration.java b/aai-resources/src/test/java/org/onap/aai/it/multitenancy/KeycloakTestConfiguration.java deleted file mode 100644 index 1e47c42d..00000000 --- a/aai-resources/src/test/java/org/onap/aai/it/multitenancy/KeycloakTestConfiguration.java +++ /dev/null @@ -1,72 +0,0 @@ -/** - * ============LICENSE_START======================================================= - * org.onap.aai - * ================================================================================ - * Copyright © 2017-2018 AT&T Intellectual Property. All rights reserved. - * ================================================================================ - * 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. - * ============LICENSE_END========================================================= - */ - -package org.onap.aai.it.multitenancy; - -import com.github.dockerjava.api.model.ExposedPort; -import com.github.dockerjava.api.model.HostConfig; -import com.github.dockerjava.api.model.PortBinding; -import com.github.dockerjava.api.model.Ports; - -import dasniko.testcontainers.keycloak.KeycloakContainer; - -import org.keycloak.adapters.springboot.KeycloakSpringBootProperties; -import org.keycloak.admin.client.Keycloak; -import org.keycloak.admin.client.KeycloakBuilder; -import org.keycloak.representations.adapters.config.AdapterConfig; -import org.springframework.boot.test.context.TestConfiguration; -import org.springframework.context.annotation.Bean; - -@TestConfiguration -class KeycloakTestConfiguration { - - @Bean - public AdapterConfig adapterConfig() { - return new KeycloakSpringBootProperties(); - } - - @Bean - KeycloakContainer keycloakContainer(KeycloakTestProperties properties) { - KeycloakContainer keycloak = - new KeycloakContainer("jboss/keycloak:12.0.4").withRealmImportFile(properties.realmJson) - .withCreateContainerCmdModifier(cmd -> cmd.withHostConfig(new HostConfig().withPortBindings( - new PortBinding(Ports.Binding.bindPort(Integer.parseInt(properties.port)), - new ExposedPort(8080))))); - keycloak.start(); - return keycloak; - } - - @Bean - Keycloak keycloakAdminClient(KeycloakContainer keycloak, KeycloakTestProperties properties) { - return KeycloakBuilder.builder().serverUrl(keycloak.getAuthServerUrl()).realm(properties.realm) - .clientId(properties.adminCli).username(keycloak.getAdminUsername()) - .password(keycloak.getAdminPassword()).build(); - } - - @Bean - RoleHandler roleHandler(Keycloak adminClient, KeycloakTestProperties properties) { - return new RoleHandler(adminClient, properties); - } - - @Bean - KeycloakTestProperties properties() { - return new KeycloakTestProperties(); - } -} diff --git a/aai-resources/src/test/java/org/onap/aai/it/multitenancy/KeycloakTestProperties.java b/aai-resources/src/test/java/org/onap/aai/it/multitenancy/KeycloakTestProperties.java deleted file mode 100644 index 7f1e34ce..00000000 --- a/aai-resources/src/test/java/org/onap/aai/it/multitenancy/KeycloakTestProperties.java +++ /dev/null @@ -1,45 +0,0 @@ -/** - * ============LICENSE_START======================================================= - * org.onap.aai - * ================================================================================ - * Copyright © 2017-2018 AT&T Intellectual Property. All rights reserved. - * ================================================================================ - * 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. - * ============LICENSE_END========================================================= - */ - -package org.onap.aai.it.multitenancy; - -import org.springframework.beans.factory.annotation.Value; - -class KeycloakTestProperties { - - @Value("${test.keycloak.realm.json}") - public String realmJson; - - @Value("${keycloak.realm}") - public String realm; - - @Value("${keycloak.resource}") - public String clientId; - - @Value("${test.keycloak.client.secret}") - public String clientSecret; - - @Value("${test.keycloak.admin.cli}") - public String adminCli; - - @Value("${test.keycloak.auth-server-port}") - public String port; - -} diff --git a/aai-resources/src/test/java/org/onap/aai/it/multitenancy/MultiTenancyIT.java b/aai-resources/src/test/java/org/onap/aai/it/multitenancy/MultiTenancyIT.java deleted file mode 100644 index 892b8e3e..00000000 --- a/aai-resources/src/test/java/org/onap/aai/it/multitenancy/MultiTenancyIT.java +++ /dev/null @@ -1,124 +0,0 @@ -/** - * ============LICENSE_START================================================== - * org.onap.aai - * =========================================================================== - * Copyright © 2017-2020 AT&T Intellectual Property. All rights reserved. - * =========================================================================== - * 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. - * ============LICENSE_END==================================================== - */ - -package org.onap.aai.it.multitenancy; - -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertNotNull; - -import dasniko.testcontainers.keycloak.KeycloakContainer; -import org.junit.jupiter.api.Test; - -import java.util.Collections; - -import org.keycloak.admin.client.Keycloak; -import org.keycloak.admin.client.KeycloakBuilder; -import org.keycloak.representations.AccessTokenResponse; -import org.onap.aai.PayloadUtil; -import org.onap.aai.rest.AbstractSpringRestTest; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.context.annotation.Import; -import org.springframework.http.HttpEntity; -import org.springframework.http.HttpHeaders; -import org.springframework.http.HttpMethod; -import org.springframework.http.HttpStatus; -import org.springframework.http.MediaType; -import org.springframework.http.ResponseEntity; -import org.springframework.test.context.TestPropertySource; - -@Import(KeycloakTestConfiguration.class) -@TestPropertySource(locations = "classpath:it/application-keycloak-test.properties") -public class MultiTenancyIT extends AbstractSpringRestTest { - - @Autowired - private KeycloakContainer keycloakContainer; - @Autowired - private RoleHandler roleHandler; - @Autowired - private KeycloakTestProperties properties; - - @Test - public void testCreateAndGetPnf() throws Exception { - baseUrl = "http://localhost:" + randomPort; - String endpoint = baseUrl + "/aai/v23/network/pnfs/pnf/pnf-1"; - ResponseEntity<String> responseEntity = null; - - // create pnf with ran (operator) - String username = "ran", password = "ran"; - headers = this.getHeaders(username, password); - httpEntity = new HttpEntity<String>(PayloadUtil.getResourcePayload("pnf.json"), headers); - responseEntity = restTemplate.exchange(endpoint, HttpMethod.PUT, httpEntity, String.class); - assertEquals(HttpStatus.CREATED, responseEntity.getStatusCode()); - - // get pnf with bob (operator_readOnly) - username = "bob"; - password = "bob"; - headers = this.getHeaders(username, password); - httpEntity = new HttpEntity<String>("", headers); - responseEntity = restTemplate.exchange(endpoint, HttpMethod.GET, httpEntity, String.class); - assertEquals(HttpStatus.OK, responseEntity.getStatusCode()); - - // get pnf with ted (selector) - username = "ted"; - password = "ted"; - headers = this.getHeaders(username, password); - httpEntity = new HttpEntity<String>("", headers); - responseEntity = restTemplate.exchange(endpoint, HttpMethod.GET, httpEntity, String.class); - assertEquals(HttpStatus.FORBIDDEN, responseEntity.getStatusCode()); - - // add role to ted and try to get pnf again - roleHandler.addToUser(RoleHandler.OPERATOR_READ_ONLY, username); - headers = this.getHeaders(username, password); - httpEntity = new HttpEntity<String>("", headers); - responseEntity = restTemplate.exchange(endpoint, HttpMethod.GET, httpEntity, String.class); - assertEquals(HttpStatus.OK, responseEntity.getStatusCode()); - - // get pnf with ran - username = "ran"; - password = "ran"; - headers = this.getHeaders(username, password); - httpEntity = new HttpEntity<String>("", headers); - responseEntity = restTemplate.exchange(endpoint, HttpMethod.GET, httpEntity, String.class); - assertEquals(HttpStatus.OK, responseEntity.getStatusCode()); - } - - private HttpHeaders getHeaders(String username, String password) { - HttpHeaders headers = new HttpHeaders(); - - headers.setContentType(MediaType.APPLICATION_JSON); - headers.setAccept(Collections.singletonList(MediaType.APPLICATION_JSON)); - headers.add("Real-Time", "true"); - headers.add("X-FromAppId", "JUNIT"); - headers.add("X-TransactionId", "JUNIT"); - headers.add("Authorization", "Bearer " + getStringToken(username, password)); - - return headers; - } - - private String getStringToken(String username, String password) { - Keycloak keycloakClient = KeycloakBuilder.builder().serverUrl(keycloakContainer.getAuthServerUrl()) - .realm(properties.realm).clientId(properties.clientId).clientSecret(properties.clientSecret) - .username(username).password(password).build(); - - AccessTokenResponse tokenResponse = keycloakClient.tokenManager().getAccessToken(); - assertNotNull(tokenResponse); - return tokenResponse.getToken(); - } -} diff --git a/aai-resources/src/test/java/org/onap/aai/it/multitenancy/RoleHandler.java b/aai-resources/src/test/java/org/onap/aai/it/multitenancy/RoleHandler.java deleted file mode 100644 index c9c1fd23..00000000 --- a/aai-resources/src/test/java/org/onap/aai/it/multitenancy/RoleHandler.java +++ /dev/null @@ -1,54 +0,0 @@ -/** - * ============LICENSE_START======================================================= - * org.onap.aai - * ================================================================================ - * Copyright © 2017-2018 AT&T Intellectual Property. All rights reserved. - * ================================================================================ - * 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. - * ============LICENSE_END========================================================= - */ - -package org.onap.aai.it.multitenancy; - -import java.util.Collections; - -import org.keycloak.admin.client.Keycloak; -import org.keycloak.admin.client.resource.RealmResource; - -class RoleHandler { - - /** - * Following roles should be the same as given roles in multi-tenancy-realm json file - */ - final static String OPERATOR = "operator"; - final static String OPERATOR_READ_ONLY = "operator_readOnly"; - private final Keycloak adminClient; - private final KeycloakTestProperties properties; - - RoleHandler(Keycloak adminClient, KeycloakTestProperties properties) { - this.adminClient = adminClient; - this.properties = properties; - } - - void addToUser(String role, String username) { - RealmResource realm = adminClient.realm(properties.realm); - realm.users().get(username).roles().realmLevel() - .add(Collections.singletonList(realm.roles().get(role).toRepresentation())); - } - - void removeFromUser(String role, String username) { - RealmResource realm = adminClient.realm(properties.realm); - realm.users().get(username).roles().realmLevel() - .remove(Collections.singletonList(realm.roles().get(role).toRepresentation())); - } -} diff --git a/aai-resources/src/test/java/org/onap/aai/rest/AbstractSpringRestTest.java b/aai-resources/src/test/java/org/onap/aai/rest/AbstractSpringRestTest.java index adfa433a..edf905ee 100644 --- a/aai-resources/src/test/java/org/onap/aai/rest/AbstractSpringRestTest.java +++ b/aai-resources/src/test/java/org/onap/aai/rest/AbstractSpringRestTest.java @@ -36,7 +36,6 @@ import org.onap.aai.ResourcesTestConfiguration; import org.onap.aai.dbmap.AAIGraph; import org.onap.aai.exceptions.AAIException; import org.onap.aai.nodes.NodeIngestor; -import org.onap.aai.restclient.PropertyPasswordConfiguration; import org.onap.aai.util.AAIConfig; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.autoconfigure.EnableAutoConfiguration; @@ -54,7 +53,7 @@ import org.springframework.web.client.RestTemplate; @Import(ResourcesTestConfiguration.class) @TestPropertySource(locations = "classpath:application-test.properties") -@ContextConfiguration(initializers = PropertyPasswordConfiguration.class) +@ContextConfiguration @EnableAutoConfiguration(exclude = {CassandraDataAutoConfiguration.class, CassandraAutoConfiguration.class}) // there is no running cassandra instance for the test @SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT, classes = ResourcesApp.class) public abstract class AbstractSpringRestTest { diff --git a/aai-resources/src/test/java/org/onap/aai/rest/AuthenticationTest.java b/aai-resources/src/test/java/org/onap/aai/rest/AuthenticationTest.java new file mode 100644 index 00000000..446b3757 --- /dev/null +++ b/aai-resources/src/test/java/org/onap/aai/rest/AuthenticationTest.java @@ -0,0 +1,78 @@ +/** + * ============LICENSE_START======================================================= + * org.onap.aai + * ================================================================================ + * Copyright © 2025 Deutsche Telekom. All rights reserved. + * ================================================================================ + * 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. + * ============LICENSE_END========================================================= + */ + +package org.onap.aai.rest; + +import java.time.Duration; +import java.util.Collections; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.onap.aai.config.AuthProperties; +import org.onap.aai.config.WebClientConfiguration; +import org.onap.aai.setup.SchemaVersions; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.boot.test.context.SpringBootTest.WebEnvironment; +import org.springframework.boot.test.web.server.LocalServerPort; +import org.springframework.context.annotation.Import; +import org.springframework.http.MediaType; +import org.springframework.test.web.reactive.server.WebTestClient; + +@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT) +@Import(WebClientConfiguration.class) +public class AuthenticationTest { + + @Autowired AuthProperties authProperties; + @Autowired SchemaVersions schemaVersions; + @LocalServerPort int port; + + WebTestClient webClient; + + @BeforeEach + void setup() { + webClient = WebTestClient.bindToServer() + .baseUrl("http://localhost:" + port + "/aai/" + schemaVersions.getDefaultVersion()) + .responseTimeout(Duration.ofSeconds(300)) + .defaultHeaders(headers -> { + headers.setAccept(Collections.singletonList(MediaType.APPLICATION_JSON)); + headers.set("X-FromAppId", "test"); + headers.set("X-TransactionId", "someTransaction"); + }) + .build(); + } + + @Test + void thatServiceIsAuthenticated() { + webClient.get() + .uri("/cloud-infrastructure/pservers/pserver/pserver-hostname-test") + .exchange() + .expectStatus() + .isForbidden(); + + webClient.get() + .uri("/cloud-infrastructure/pservers/pserver/pserver-hostname-test") + .headers(headers -> headers.setBasicAuth(authProperties.getUsers().get(0).getUsername(), authProperties.getUsers().get(0).getPassword())) + .exchange() + .expectStatus() + .isNotFound(); + } + +} diff --git a/aai-resources/src/test/java/org/onap/aai/rest/ConfigurationTest.java b/aai-resources/src/test/java/org/onap/aai/rest/ConfigurationTest.java index 15c03cf8..51ab2aa1 100644 --- a/aai-resources/src/test/java/org/onap/aai/rest/ConfigurationTest.java +++ b/aai-resources/src/test/java/org/onap/aai/rest/ConfigurationTest.java @@ -35,7 +35,6 @@ import org.junit.jupiter.api.Test; import org.onap.aai.ResourcesApp; import org.onap.aai.ResourcesTestConfiguration; import org.onap.aai.config.SpringContextAware; -import org.onap.aai.restclient.PropertyPasswordConfiguration; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; import org.springframework.boot.autoconfigure.EnableAutoConfiguration; @@ -61,7 +60,7 @@ import org.springframework.web.client.RestTemplate; @AutoConfigureMetrics @TestPropertySource(locations = "classpath:application-test.properties") -@ContextConfiguration(initializers = PropertyPasswordConfiguration.class, classes = {SpringContextAware.class}) +@ContextConfiguration(classes = {SpringContextAware.class}) @EnableAutoConfiguration(exclude={CassandraDataAutoConfiguration.class, CassandraAutoConfiguration.class}) // there is no running cassandra instance for the test @Import(ResourcesTestConfiguration.class) @SpringBootTest( diff --git a/aai-resources/src/test/java/org/onap/aai/rest/resources/ResourcesControllerTest.java b/aai-resources/src/test/java/org/onap/aai/rest/resources/ResourcesControllerTest.java index da7c0647..6d0dcbf1 100644 --- a/aai-resources/src/test/java/org/onap/aai/rest/resources/ResourcesControllerTest.java +++ b/aai-resources/src/test/java/org/onap/aai/rest/resources/ResourcesControllerTest.java @@ -99,71 +99,11 @@ import reactor.core.publisher.Mono; public class ResourcesControllerTest { private static final Logger logger = LoggerFactory.getLogger(ResourcesController.class.getName()); - private static final Set<Integer> VALID_HTTP_STATUS_CODES = new HashSet<>(); - protected static final MediaType APPLICATION_JSON = MediaType.valueOf("application/json"); - - static { - VALID_HTTP_STATUS_CODES.add(200); - VALID_HTTP_STATUS_CODES.add(201); - VALID_HTTP_STATUS_CODES.add(204); - } + private static final ObjectMapper mapper = new ObjectMapper(); @Autowired WebTestClient webClient; @Autowired SchemaVersions schemaVersions; - ObjectMapper mapper = new ObjectMapper(); - - private ResourcesController resourcesController; - private HttpHeaders httpHeaders; - private UriInfo uriInfo; - private MultivaluedMap<String, String> headersMultiMap; - private MultivaluedMap<String, String> queryParameters; - private List<String> aaiRequestContextList; - private List<MediaType> outputMediaTypes; - private String defaultSchemaVersion; - - @BeforeEach - public void setup() throws AAIException { - if(!AAIGraph.isInit()) { - AAIConfig.init(); - AAIGraph.getInstance(); - } - logger.info("Starting the setup for the integration tests of Rest Endpoints"); - - resourcesController = new ResourcesController(new ResourcesService()); - httpHeaders = Mockito.mock(HttpHeaders.class); - uriInfo = Mockito.mock(UriInfo.class); - - headersMultiMap = new MultivaluedHashMap<>(); - queryParameters = Mockito.spy(new MultivaluedHashMap<>()); - - headersMultiMap.add("X-FromAppId", "JUNIT"); - headersMultiMap.add("X-TransactionId", UUID.randomUUID().toString()); - headersMultiMap.add("Real-Time", "true"); - headersMultiMap.add("Accept", "application/json"); - headersMultiMap.add("aai-request-context", ""); - - outputMediaTypes = new ArrayList<>(); - outputMediaTypes.add(APPLICATION_JSON); - - aaiRequestContextList = new ArrayList<>(); - aaiRequestContextList.add(""); - defaultSchemaVersion = schemaVersions.getDefaultVersion().toString(); - - when(httpHeaders.getAcceptableMediaTypes()).thenReturn(outputMediaTypes); - when(httpHeaders.getRequestHeaders()).thenReturn(headersMultiMap); - - when(httpHeaders.getRequestHeader("aai-request-context")).thenReturn(aaiRequestContextList); - - when(uriInfo.getQueryParameters()).thenReturn(queryParameters); - when(uriInfo.getQueryParameters(false)).thenReturn(queryParameters); - - // TODO - Check if this is valid since RemoveDME2QueryParameters seems to be very unreasonable - Mockito.doReturn(null).when(queryParameters).remove(any()); - - when(httpHeaders.getMediaType()).thenReturn(APPLICATION_JSON); - } - @AfterEach public void tearDown() { JanusGraph janusGraph = AAIGraph.getInstance().getGraph(); @@ -423,11 +363,6 @@ public class ResourcesControllerTest { String patchData = "{\"in-maint\": false}"; - headersMultiMap.add("Content-Type", "application/json"); - - outputMediaTypes.remove(APPLICATION_JSON); - outputMediaTypes.add(MediaType.valueOf("application/merge-patch+json")); - webClient.patch() .uri(uri) .header("Content-Type", "application/merge-patch+json") @@ -496,12 +431,12 @@ public class ResourcesControllerTest { public String getResourcePayload(String resourceName) throws IOException { String rawPayload = IOUtils.toString(this.getClass().getResourceAsStream("/payloads/resource/" + resourceName + ".json"), StandardCharsets.UTF_8); - return String.format(rawPayload, defaultSchemaVersion); + return String.format(rawPayload, schemaVersions.getDefaultVersion()); } public String getRelationshipPayload(String relationshipName) throws IOException { String rawPayload = IOUtils.toString(this.getClass().getResourceAsStream("/payloads/relationship/" + relationshipName + ".json"), StandardCharsets.UTF_8); - return String.format(rawPayload, defaultSchemaVersion); + return String.format(rawPayload, schemaVersions.getDefaultVersion()); } public String getUri(String hostname) { diff --git a/aai-resources/src/test/resources/application-test.properties b/aai-resources/src/test/resources/application-test.properties index 622715d8..e2b11ad2 100644 --- a/aai-resources/src/test/resources/application-test.properties +++ b/aai-resources/src/test/resources/application-test.properties @@ -16,7 +16,6 @@ spring.sleuth.enabled=false spring.autoconfigure.exclude=\ org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration,\ org.springframework.boot.autoconfigure.orm.jpa.HibernateJpaAutoConfiguration,\ - org.keycloak.adapters.springboot.KeycloakAutoConfiguration,\ org.springframework.boot.autoconfigure.security.servlet.SecurityAutoConfiguration,\ org.springframework.boot.actuate.autoconfigure.security.servlet.ManagementWebSecurityAutoConfiguration @@ -28,17 +27,7 @@ server.tomcat.threads.min-spare=25 server.tomcat.max-idle-time=60000 server.local.startpath=src/main/resources/ -server.basic.auth.location=${server.local.startpath}etc/auth/realm.properties - server.port=8447 -server.ssl.enabled=false -#server.ssl.enabled-protocols=TLSv1.1,TLSv1.2 -#server.ssl.key-store=${server.local.startpath}etc/auth/aai_keystore -#server.ssl.key-store-password=password(OBF:1vn21ugu1saj1v9i1v941sar1ugw1vo0) -#server.ssl.trust-store=${server.local.startpath}etc/auth/aai_keystore -#server.ssl.trust-store-password=password(OBF:1vn21ugu1saj1v9i1v941sar1ugw1vo0) -#server.ssl.client-auth=want -#server.ssl.key-store-type=JKS # Removed deprecated DMaaP reference # dmaap.ribbon.listOfServers=localhost:3904 @@ -82,3 +71,6 @@ scrape.uri.metrics=true aai.notifications.enabled=false aai.graph.properties.path=src/test/resources/etc/appprops/janusgraph-realtime.properties +aai.basic-auth.enabled=true +aai.basic-auth.users[0].username=AAI +aai.basic-auth.users[0].password=AAI diff --git a/aai-resources/src/test/resources/it/application-keycloak-test.properties b/aai-resources/src/test/resources/it/application-keycloak-test.properties deleted file mode 100644 index 6fff1c1c..00000000 --- a/aai-resources/src/test/resources/it/application-keycloak-test.properties +++ /dev/null @@ -1,17 +0,0 @@ -test.keycloak.realm.json=it/multi-tenancy-realm.json -test.keycloak.client.secret=secret -test.keycloak.admin.cli=admin-cli -test.keycloak.auth-server-port=58180 - -keycloak.auth-server-url=http://localhost:58180/auth -keycloak.realm=aai-resources -keycloak.resource=aai-resources-app -keycloak.public-client=true -keycloak.principal-attribute=preferred_username - -keycloak.ssl-required=external -keycloak.bearer-only=true - -multi.tenancy.enabled=true -spring.profiles.active=production,keycloak -schema.version.list=v10,v11,v12,v13,v14,v29,v30 diff --git a/aai-resources/src/test/resources/it/multi-tenancy-realm.json b/aai-resources/src/test/resources/it/multi-tenancy-realm.json deleted file mode 100644 index 401187b2..00000000 --- a/aai-resources/src/test/resources/it/multi-tenancy-realm.json +++ /dev/null @@ -1,173 +0,0 @@ -{ - "id": "aai-resources", - "realm": "aai-resources", - "notBefore": 0, - "revokeRefreshToken": false, - "refreshTokenMaxReuse": 0, - "accessTokenLifespan": 300, - "accessTokenLifespanForImplicitFlow": 900, - "ssoSessionIdleTimeout": 1800, - "ssoSessionMaxLifespan": 36000, - "ssoSessionIdleTimeoutRememberMe": 0, - "ssoSessionMaxLifespanRememberMe": 0, - "offlineSessionIdleTimeout": 2592000, - "offlineSessionMaxLifespanEnabled": false, - "offlineSessionMaxLifespan": 5184000, - "clientSessionIdleTimeout": 0, - "clientSessionMaxLifespan": 0, - "clientOfflineSessionIdleTimeout": 0, - "clientOfflineSessionMaxLifespan": 0, - "accessCodeLifespan": 60, - "accessCodeLifespanUserAction": 300, - "accessCodeLifespanLogin": 1800, - "actionTokenGeneratedByAdminLifespan": 43200, - "actionTokenGeneratedByUserLifespan": 300, - "enabled": true, - "sslRequired": "external", - "registrationAllowed": false, - "registrationEmailAsUsername": false, - "rememberMe": false, - "verifyEmail": false, - "loginWithEmailAllowed": true, - "duplicateEmailsAllowed": false, - "resetPasswordAllowed": false, - "editUsernameAllowed": false, - "bruteForceProtected": false, - "permanentLockout": false, - "maxFailureWaitSeconds": 900, - "minimumQuickLoginWaitSeconds": 60, - "waitIncrementSeconds": 60, - "quickLoginCheckMilliSeconds": 1000, - "maxDeltaTimeSeconds": 43200, - "failureFactor": 30, - "users": [ - { - "username": "admin", - "enabled": true, - "credentials": [ - { - "type": "password", - "value": "admin" - } - ], - "clientRoles": { - "realm-management": ["manage-users", "view-clients", "view-realm", "view-users"] - } - }, - { - "id": "ran", - "username": "ran", - "enabled": true, - "credentials": [ - { - "type": "password", - "value": "ran" - } - ], - "realmRoles": [ - "operator" - ] - }, - { - "id": "bob", - "username": "bob", - "enabled": true, - "credentials": [ - { - "type": "password", - "value": "bob" - } - ], - "realmRoles": [ - "operator_readOnly" - ] - }, - { - "id": "ted", - "username": "ted", - "enabled": true, - "credentials": [ - { - "type": "password", - "value": "ted" - } - ], - "realmRoles": [ - "selector" - ] - } - ], - "roles": { - "realm": [ - { - "name": "operator", - "description": "Operator privileges" - }, - { - "name": "operator_readOnly", - "description": "Operator's read only privileges" - }, - { - "name": "selector", - "description": "Selector privileges" - }, - { - "name": "selector_readOnly", - "description": "Selector's read only privileges" - }, - { - "name": "admin", - "description": "Administrator privileges" - } - ] - }, - "clients": [ - { - "clientId": "aai-resources-app", - "enabled": true, - "secret": "secret", - "directAccessGrantsEnabled": true, - "authorizationServicesEnabled": true, - "authorizationSettings": { - "allowRemoteResourceManagement": true, - "policyEnforcementMode": "ENFORCING" - } - } - ], - "defaultDefaultClientScopes": [ - "roles", - "email", - "web-origins", - "profile", - "role_list" - ], - "clientScopes": [ - { - "id": "0f7dfd8b-c230-4664-8d77-da85bcc4fe2a", - "name": "roles", - "description": "OpenID Connect scope for add user roles to the access token", - "protocol": "openid-connect", - "attributes": { - "include.in.token.scope": "true", - "display.on.consent.screen": "true", - "consent.screen.text": "${rolesScopeConsentText}" - }, - "protocolMappers": [ - { - "id": "4b9f8798-8990-4c0d-87d3-034e72655e3b", - "name": "realm roles", - "protocol": "openid-connect", - "protocolMapper": "oidc-usermodel-realm-role-mapper", - "consentRequired": false, - "config": { - "multivalued": "true", - "user.attribute": "foo", - "access.token.claim": "true", - "claim.name": "realm_access.roles", - "jsonType.label": "String" - } - } - ] - } - ] -}
\ No newline at end of file @@ -26,11 +26,11 @@ <parent> <groupId>org.onap.aai.aai-common</groupId> <artifactId>aai-parent</artifactId> - <version>1.15.4</version> + <version>1.15.5-SNAPSHOT</version> </parent> <groupId>org.onap.aai.resources</groupId> <artifactId>resources</artifactId> - <version>1.15.4-SNAPSHOT</version> + <version>1.15.5-SNAPSHOT</version> <name>aai-resources</name> <packaging>pom</packaging> <modules> @@ -49,7 +49,7 @@ <staging.path>/content/repositories/staging/</staging.path> <!-- GMaven plugin uses this property to figure out the name of the docker tag --> <aai.project.version>${project.version}</aai.project.version> - <aai.common.version>1.15.4</aai.common.version> + <aai.common.version>1.15.5-SNAPSHOT</aai.common.version> <aai.schema.service.version>1.12.7</aai.schema.service.version> </properties> <build> diff --git a/version.properties b/version.properties index 08fc17cd..73ddb41f 100644 --- a/version.properties +++ b/version.properties @@ -5,7 +5,7 @@ major_version=1 minor_version=15 -patch_version=3 +patch_version=5 base_version=${major_version}.${minor_version}.${patch_version} |