armeria icon indicating copy to clipboard operation
armeria copied to clipboard

Provide a way to specify a regex for allowed origins

Open minwoox opened this issue 1 year ago • 8 comments

Currently, we use the exact match for the allowed origin: https://github.com/line/armeria/blob/5b384fbe27e7e6f9225d6db91cbb684d09dfbb5e/core/src/main/java/com/linecorp/armeria/server/cors/CorsConfig.java#L108 This can be a problem if there are tremendous subdomains that are frequently changed because users cannot specify all of them.

minwoox avatar Jun 16 '23 01:06 minwoox

Please assign this to me ~ 🥺

seonWKim avatar Jun 16 '23 08:06 seonWKim

It's all yours. Thanks! 😆

minwoox avatar Jun 16 '23 09:06 minwoox

@minwoox Thank you for assigning the issue to me 😄 . I have a question about the issue.

It seems that armeria allow users to configure CORS in below ways:

  • CorsService's builder(String...origins)
  • CorsDecorator annotation's origins

Should we provide features that allow users to configure origins using regex by adding additional field such as originPatterns or just consider the origin String as a regex expression ?

seonWKim avatar Jun 18 '23 05:06 seonWKim

We are specifying the origin when we create the builder so I prefer to specify the regex when creating a builder:

CorsService.builderForRegex("^https:\\/\\/.*example.com$")
           .allowRequestMethods(HttpMethod.POST, HttpMethod.GET)
           .andForOriginRegex("^https:\\/\\/.*example2.com$")
           .allowRequestMethods(HttpMethod.GET)
           .and()
           .newDecorator()));
// Use Pattern
Pattern regex = ...
CorsService.builderForRegex(regex)
           .allowRequestMethods(HttpMethod.POST, HttpMethod.GET)
           ...

We can also specify the regex string to @CorsDecoror

@CorsDecorator(
  originRegex = "^https:\\/\\/.*example.com$",
  pathPatterns = "glob:/**/configured",
  allowedRequestMethods = HttpMethod.GET
)

We can also add a predicate for the builder only. (Not for the annotation)

Predicate predicate = ...
CorsService.builder(predicate)
           .allowRequestMethods(HttpMethod.POST, HttpMethod.GET)

minwoox avatar Jun 19 '23 05:06 minwoox

Thank you for your detailed comment. I want to make sure that I understand what features are needed 😄 . Are below features the ones that should be implemented ?

  1. Add methods to indicate regex in the CorsService and CorsServiceBuilder (e.g. builderForRegex, andForOriginRegex and some overloaded methods)
  2. Add originRegex for CorsDecorator annotaion
  3. Accept Predicate in CorsService.builder(...) method.

seonWKim avatar Jun 19 '23 07:06 seonWKim

Yes, exactly. 😄 We also need to add those methods to CorsPolicy:

class CorsService {

    public static CorsServiceBuilder builder(Predicate<String> predicate) {...}
    // Need to consider a better name.
    public static CorsServiceBuilder builderForOriginRegex(String regex) {...}
    public static CorsServiceBuilder builderForOriginRegex(Pattern regex) {...}
}

class CorsServiceBuilder {

    CorsServiceBuilder(Predicate<String> predicate) {...}
    CorsServiceBuilder(Pattern regex) {...}

    public ChainedCorsPolicyBuilder andForOriginRegex(String regex) {...}
    public ChainedCorsPolicyBuilder andForOriginRegex(Pattern regex) {...}
}

class CorsPolicy {
    public static CorsPolicyBuilder builder(Predicate<String> predicate) {...}
    public static CorsPolicyBuilder builderForOriginRegex(String regex) {...}
    public static CorsPolicyBuilder builderForOriginRegex(Pattern regex) {...}
}

class CorsPolicyBuilder {

    CorsPolicyBuilder(Predicate<String> predicate) {...}
    CorsPolicyBuilder(Pattern regex) {...}
}

public @interface CorsDecorator {
    String[] origins();
    String originRegex(); // We could probably raise an exception if both origins and originRegex are specified.
    ...
}

We also need to make WebSockerServiceBuilder support the Predicate. We don't have to support the regex because unlike CorsDecorator, it doesn't have an annotation which the value should be specified in String.

class WebSocketServiceBuilder {
    public WebSocketServiceBuilder allowedOrigins(Predicate<String> predicate) {...}
}

minwoox avatar Jun 19 '23 08:06 minwoox

Hi @minwoox , thank you for the super detailed and wonderful explanation. I wonder what policy we should take.

  • Allow users to specify origins, originRegex and predicate at the same time.
    • If so, when we verify a origin, what's the policy for verifying allowed origins ?
      • user requested origins should match: origins AND originRegex AND predicate
      • user requested origins should match: origins OR originRegex OR predicate
  • Allow users to specify only one of origins, originRegex or `predicate.

Based on the comment you wrote in below code, it seems that we might not want users to specify both origins and originRegex at the same time.


public @interface CorsDecorator {
    String[] origins();
    String originRegex(); // We could probably raise an exception if both origins and originRegex are specified.
    ...
}

seonWKim avatar Jun 21 '23 23:06 seonWKim

Allow users to specify only one of origins, originRegex or `predicate.

This is what I'm saying. regex or Predicate can cover multiple domains so I think we don't have to provide a way to chain those conditions. Predicate even has its own and and or methods, so users can chain them if they want.

minwoox avatar Jun 22 '23 01:06 minwoox

closed by https://github.com/line/armeria/pull/4982

jrhee17 avatar Apr 08 '24 05:04 jrhee17