Repository: micronaut-projects/micronaut-core
Issue: New allowed-origins-regex property not working..?

### Expected Behavior

With 3.9.0 allowed-origins no longer supports a regex value for the cors configuration. Instead you now need to use a new property called allowed-origins-regex.

When replacing allowed-origins with allowed-origins-regex using the same regular expression and previously, it's expected that calls from an Origin matching the pattern are allowed through.

### Actual Behaviour

Calls with a matching Origin header are no longer accepted and a 403 forbidden is returned.

### Steps To Reproduce

Start a 3.8.9 micronaut server with a configuration set to 

```
micronaut:
    application:
        name: testApp
    server:
        cors:
            enabled: true
            configurations:
                web:
                    allowed-origins: 
                      - ^http(|s):\\/\\/(\\w*\\.)*integration\\.mydomain\\.com$
```

Make a call to an endpoint on that server specifying an Origin value in the header of "https://www.integration.mydomain.com"

You should receive a 200 okay.

Now change the configuration to the below and the version of Micronaut to 3.9.x
```
micronaut:
    application:
        name: testApp
    server:
        cors:
            enabled: true
            configurations:
                web:
                    allowed-origins-regex: ^http(|s):\\/\\/(\\w*\\.)*integration\\.mydomain\\.com$
```

Make the same call to an endpoint and you should receive a 403 Forbidden. (Expected that you receive a 200)

### Environment Information

macOS
JDK 17
Micronaut 3.8.9 and 3.9.2

### Example Application

_No response_

### Version

3.9.2

Changed files:
http-server-tck/src/main/java/io/micronaut/http/server/tck/tests/cors/CorsSimpleRequestTest.java
http-server/src/main/java/io/micronaut/http/server/cors/CorsFilter.java

diff --git a/http-server-tck/src/main/java/io/micronaut/http/server/tck/tests/cors/CorsSimpleRequestTest.java b/http-server-tck/src/main/java/io/micronaut/http/server/tck/tests/cors/CorsSimpleRequestTest.java
index 6dc7342aad..33278f69cc 100644
--- a/http-server-tck/src/main/java/io/micronaut/http/server/tck/tests/cors/CorsSimpleRequestTest.java
+++ b/http-server-tck/src/main/java/io/micronaut/http/server/tck/tests/cors/CorsSimpleRequestTest.java
@@ -1,5 +1,5 @@
 /*
- * Copyright 2017-2022 original authors
+ * Copyright 2017-2023 original authors
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -184,22 +184,42 @@ public class CorsSimpleRequestTest {
                 "micronaut.server.cors.configurations.foo.allowed-origins", Collections.singletonList("https://foo.com")
             ),
             createRequest("https://foo.com"),
-            (server, request) -> {
+            CorsSimpleRequestTest::isSuccessfulCorsAssertion
+        );
+    }
 
-                RefreshCounter refreshCounter = server.getApplicationContext().getBean(RefreshCounter.class);
-                assertEquals(0, refreshCounter.getRefreshCount());
+    /**
+     * CORS Simple request for localhost can be allowed via configuration of a regex.
+     * @throws IOException may throw the try for resources
+     */
+    @Test
+    // "https://github.com/micronaut-projects/micronaut-core/issues/9423")
+    void corsSimpleRequestForLocalhostCanBeAllowedViaRegexConfiguration() throws IOException {
+        asserts(SPECNAME,
+            CollectionUtils.mapOf(
+                PROPERTY_MICRONAUT_SERVER_CORS_ENABLED, StringUtils.TRUE,
+                "micronaut.server.cors.configurations.foo.allowed-origins-regex", Collections.singletonList("^http(|s):\\\\/\\\\/foo\\\\.com$")
+            ),
+            createRequest("https://foo.com"),
+            CorsSimpleRequestTest::isSuccessfulCorsAssertion
+        );
+    }
 
-                AssertionUtils.assertDoesNotThrow(server, request, HttpResponseAssertion.builder()
-                    .status(HttpStatus.OK)
-                    .assertResponse(response -> CorsAssertion.builder()
-                        .vary("Origin")
-                        .allowCredentials()
-                        .allowOrigin("https://foo.com")
-                        .build()
-                        .validate(response))
-                    .build());
-                assertEquals(1, refreshCounter.getRefreshCount());
-            });
+    /**
+     * CORS Simple request for localhost can be forbidden via configuration of a regex.
+     * @throws IOException may throw the try for resources
+     */
+    @Test
+    // "https://github.com/micronaut-projects/micronaut-core/issues/9423")
+    void corsSimpleRequestForLocalhostForbiddenViaRegexConfiguration() throws IOException {
+        asserts(SPECNAME,
+            CollectionUtils.mapOf(
+                PROPERTY_MICRONAUT_SERVER_CORS_ENABLED, StringUtils.TRUE,
+                "micronaut.server.cors.configurations.foo.allowed-origins-regex", Collections.singletonList("^http(|s):\\\\/\\\\/foo\\\\.com$")
+            ),
+            createRequest("https://bar.com"),
+            CorsSimpleRequestTest::isForbidden
+        );
     }
 
     private RequestSupplier createRequestFor(String host, String origin) {
@@ -225,6 +245,21 @@ public class CorsSimpleRequestTest {
         assertEquals(1, refreshCounter.getRefreshCount());
     }
 
+    static void isSuccessfulCorsAssertion(ServerUnderTest server, HttpRequest<?> request) {
+        RefreshCounter refreshCounter = server.getApplicationContext().getBean(RefreshCounter.class);
+        assertEquals(0, refreshCounter.getRefreshCount());
+        AssertionUtils.assertDoesNotThrow(server, request, HttpResponseAssertion.builder()
+            .status(HttpStatus.OK)
+            .assertResponse(response -> CorsAssertion.builder()
+                .vary("Origin")
+                .allowCredentials()
+                .allowOrigin("https://foo.com")
+                .build()
+                .validate(response))
+            .build());
+        assertEquals(1, refreshCounter.getRefreshCount());
+    }
+
     static HttpRequest<?> createRequest(String origin) {
         return createRequest("/refresh", origin);
     }
diff --git a/http-server/src/main/java/io/micronaut/http/server/cors/CorsFilter.java b/http-server/src/main/java/io/micronaut/http/server/cors/CorsFilter.java
index 7bf75191a3..52601235db 100644
--- a/http-server/src/main/java/io/micronaut/http/server/cors/CorsFilter.java
+++ b/http-server/src/main/java/io/micronaut/http/server/cors/CorsFilter.java
@@ -1,5 +1,5 @@
 /*
- * Copyright 2017-2020 original authors
+ * Copyright 2017-2023 original authors
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -62,6 +62,7 @@ import static io.micronaut.http.annotation.Filter.MATCH_ALL_PATTERN;
  */
 @Filter(MATCH_ALL_PATTERN)
 public class CorsFilter implements HttpServerFilter {
+
     private static final Logger LOG = LoggerFactory.getLogger(CorsFilter.class);
     private static final ArgumentConversionContext<HttpMethod> CONVERSION_CONTEXT_HTTP_METHOD = ImmutableArgumentConversionContext.of(HttpMethod.class);
 
@@ -140,7 +141,7 @@ public class CorsFilter implements HttpServerFilter {
             return false;
         }
         String host = httpHostResolver.resolve(request);
-        return isAny(corsOriginConfiguration.getAllowedOrigins()) && isHostLocal(host);
+        return isAnyOrigin(corsOriginConfiguration.getAllowedOriginsRegex().isPresent(), corsOriginConfiguration.getAllowedOrigins()) && isHostLocal(host);
     }
 
     /**
@@ -351,6 +352,11 @@ public class CorsFilter implements HttpServerFilter {
         return m.matches();
     }
 
+    private static boolean isAnyOrigin(boolean isAllowedOriginsRegexConfigured, List<String> values) {
+        // True if a regular expression has not been set for origin, and the allowed hosts are still ANY
+        return !isAllowedOriginsRegexConfigured && isAny(values);
+    }
+
     private static boolean isAny(List<String> values) {
         return values == CorsOriginConfiguration.ANY;
     }