English 中文(简体)
Securing Spring Boot REST AP with AAD and AWS Cognito for different Endpoints
原标题:Securing Spring Boot REST API with AAD and AWS Cognito for different Endpoints

希望有人能在这里帮助我,因为我无法在任何地方找到有关这个议题的任何资源。

我走过了一条春天恢复原状,目前以两种路线组合: 1. 未经许可 2. 经AAD/Entra公司批准

我的组合方法目前如下:

@Override
protected void configure(HttpSecurity http) throws Exception {
        super.configure(http);
        http.csrf().disable();
        http.authorizeRequests(requests -> requests
                .antMatchers(HttpMethod.OPTIONS, "/**/**").permitAll()
                .antMatchers("/api/protected/**").fullyAuthenticated()
                .anyRequest().permitAll()
        );
}

内容提要 AadResourceServerWeb SecurityConfigurerAdapter 。

我们以这种方式组合了我们的APIC,能够保护我们的路线如下:

@PreAuthorize("hasAuthority( APPROLE_AppName.RoleName )")
@GetMapping(value = "/some-method", produces = MediaType.APPLICATION_JSON_VALUE)
public ResponseEntity<List<String>> getStrings() {
    return ResponseEntity.ok(...);
}

我们现在应当扩大我们的APIC,以便也允许新的用户使用核准的终端点。 这些用户由AWS Cognito管理。 • 如何建立我的<密码>Web SecurityConfigurerAdapter,允许某些途径未经许可,有些则通过AAD和一些通过AWS Cognito得到保护?

主要问题是<代码>。 AadResourceServerWeb SecurityConfigurerAdapter configures the Jwt accreditation in such a way, that it only work with Breers given out by Morgan.

理想的做法是,有这样的情况:

@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class SecurityConfig extends WebSecurityConfigurerAdapter { 

    @Configuration
    @Order(1)
    public static class AzureAdSecurityConfig extends AadResourceServerWebSecurityConfigurerAdapter {

        @Override
        protected void configure(HttpSecurity http) throws Exception {
            http.authorizeRequests(requests -> requests
                    .antMatchers("/api/aad/**").fullyAuthenticated()
            );
            http.oauth2ResourceServer().jwt([UTILIZE AAD JWT VALIDATION]);
        }

    }

    @Configuration
    @Order(2)
    public static class AwsCognitoSecurityConfig extends WebSecurityConfigurerAdapter {

        @Override
        protected void configure(HttpSecurity http) throws Exception {
            http.authorizeRequests(requests -> requests
                    .antMatchers("/api/cognito/**").fullyAuthenticated()
            );
            http.oauth2ResourceServer().jwt([UTILIZE AWS COGNITO JWT VALIDATION]);
        }
    }

    @Configuration
    @Order(3)
    public static class DefaultSecurityConfig extends WebSecurityConfigurerAdapter {

            @Override
            protected void configure(HttpSecurity http) throws Exception {
                http.csrf().disable();
                http.authorizeRequests(requests -> requests
                        .antMatchers(HttpMethod.OPTIONS, "/**/**").permitAll()
                        .anyRequest().permitAll()
                );
            }
    }

}

另一个问题是<代码>。 AadResourceServerWeb SecurityConfigurerAdapter 自动为JwtClaimNames“roles”和“scp”设定了所有可能的序号。 理想的情况是,他们喜欢AAD和AWS Cognito不同,这样一来“AAD_SCOPE_”、“AAD_APPROLE_”和“COGNITO_GROUP_”作为先决条件。

我发现了一些来源,解释如何对春布特实施多端“Jwt”验证,但是它们都只使用一个数据库来执行密码/用户认证。

究竟是围绕基本上必须重新实施所有阿拉伯开发公司逻辑,以便把AWS Cognito提供的“Jwt”的验证结合起来,还是以某种方式决定路线?

我已经知道,你可以使用<代码>oauth2ResourceServer(,/code>至configure Jwt Use, but i found only information on how to implementing that for a one tenant.

If someone has already successfully implemented this specific or a similar case, or can nudge me into the right direction i would highly appreciate it. Or maybe the way i am thinking about is completely wrong, then please let me know.

问题回答

我在这里用mystarter,因为这要容易得多。

如果你更愿意使用“官方”春天起步者建立安全会议,那么,你必须提供自己的<代码>AuthenticationManagerResolver<HttpServletRequest>,使用 <>iss>,每个认证主管都拥有自己的认证转换者,与自己当局的兑换者一道处理来源要求和你想要的预定物。 Browse through my tutorials or 正式文件以获取样本和执行背后内容<0/77a href=https://acksta/6。 这一其他答案也可有所帮助(放弃不同当局的测绘需要,但类似的认证管理员决心)。

此外,这还使用了最新的春 Boo和安全版本。

<?xml version="1.0" encoding="UTF-8"?>
<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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>3.2.2</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.c4-soft.demo</groupId>
    <artifactId>multi-tenant-resource-server</artifactId>
    <version>0.0.1-SNAPSHOT</version>

    <properties>
        <java.version>21</java.version>
        <spring-addons.version>7.3.5</spring-addons.version>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-oauth2-resource-server</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>com.c4-soft.springaddons</groupId>
            <artifactId>spring-addons-starter-oidc</artifactId>
            <version>${spring-addons.version}</version>
        </dependency>

        <dependency>
            <groupId>com.c4-soft.springaddons</groupId>
            <artifactId>spring-addons-starter-oidc-test</artifactId>
            <version>${spring-addons.version}</version>
            <scope>test</scope>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>

</project>
@Configuration
@EnableMethodSecurity
public class SecurityConf {
}

Edit the following application.yaml to put their own issuers:

com:
  c4-soft:
    springaddons:
      oidc:
        ops:
        - iss: https://cognito-idp.us-west-2.amazonaws.com/us-west-2_RzhmgLwjl
          authorities:
          - path: $.cognito:groups
            prefix: COGNITO_GROUP_
        - iss: https://sts.windows.net/0a962d63-6b23-4416-81a6-29f88c553998/
          authorities:
          - path: $.appRoles.*.displayName
            prefix: AAD_APPROLE_
          - path: $.scope
            prefix: AAD_SCOPE_
        resourceserver:
          # spring-addons whitelist is for permitAll() (rather than isAuthenticated())
          # which is probably much safer
          permit-all:
          - /actuator/health/readiness
          - /actuator/health/liveness
          - /v3/api-docs/**
          - /api/public/**

以上<代码>path的数值为JSON。 您可使用jsonpath.com等工具,测试你对自己的象征性有效载荷(用jwt.io )的路标。

是的,这是容易的。 否,我没有忽略任何亚马列马法财产或瓦 Java配置(如果你不相信我的话,对新项目进行司法测试)。

Sample Controller

@RestController
public class GreetController {

    @GetMapping("/greet")
    @PreAuthorize("isAuthenticated()")
    public String getGreet(Authentication auth) {
        return "Hello %s! You are granted with %s.".formatted(auth.getName(), auth.getAuthorities());
    }

    @GetMapping(value = "/strings")
    @PreAuthorize("hasAnyAuthority( AAD_APPROLE_Admin ,  COGNITO_GROUP_admin )")
    public List<String> getStrings() {
        return List.of("protected", "strings");
    }
}

Sample Tests

@WebMvcTest(controllers = GreetController.class)
@AutoConfigureAddonsWebmvcResourceServerSecurity
@Import(SecurityConf.class)
class GreetControllerTest {
    @Autowired
    MockMvcSupport api;

    @Test
    @WithAnonymousUser
    void givenUserIsAnonymous_whenGetGreet_thenUnauthorized() throws UnsupportedEncodingException, Exception {
        api.get("/greet").andExpect(status().isUnauthorized());
    }

    @Test
    @WithJwt("aad_admin.json")
    void givenUserIsAadAdmin_whenGetGreet_thenOk() throws UnsupportedEncodingException, Exception {
        final var actual = api.get("/greet").andExpect(status().isOk()).andReturn().getResponse().getContentAsString();
        assertEquals(
            "Hello aad-admin! You are granted with [AAD_APPROLE_msiam_access, AAD_APPROLE_Admin, AAD_SCOPE_openid, AAD_SCOPE_profile, AAD_SCOPE_machin:truc].",
            actual);
    }

    @Test
    @WithJwt("cognito_admin.json")
    void givenUserIsCognitoAdmin_whenGetGreet_thenOk() throws UnsupportedEncodingException, Exception {
        final var actual = api.get("/greet").andExpect(status().isOk()).andReturn().getResponse().getContentAsString();
        assertEquals("Hello amazon-cognito-admin! You are granted with [COGNITO_GROUP_admin, COGNITO_GROUP_machin:truc].", actual);
    }

    @Test
    @WithJwt("aad_machin-truc.json")
    void givenUserIsAadMachinTruc_whenGetGreet_thenOk() throws UnsupportedEncodingException, Exception {
        final var actual = api.get("/greet").andExpect(status().isOk()).andReturn().getResponse().getContentAsString();
        assertEquals("Hello aad-user! You are granted with [AAD_APPROLE_msiam_access, AAD_SCOPE_openid, AAD_SCOPE_profile, AAD_SCOPE_machin:truc].", actual);
    }

    @Test
    @WithJwt("cognito_machin-truc.json")
    void givenUserIsCognitoMachinTruc_whenGetGreet_thenOk() throws UnsupportedEncodingException, Exception {
        final var actual = api.get("/greet").andExpect(status().isOk()).andReturn().getResponse().getContentAsString();
        assertEquals("Hello amazon-cognito-user! You are granted with [COGNITO_GROUP_machin:truc].", actual);
    }

    @Test
    @WithAnonymousUser
    void givenUserIsAnonymous_whenGetStrings_thenUnauthorized() throws UnsupportedEncodingException, Exception {
        api.get("/strings").andExpect(status().isUnauthorized());
    }

    @Test
    @WithJwt("aad_admin.json")
    void givenUserIsAadAdmin_whenGetStrings_thenOk() throws UnsupportedEncodingException, Exception {
        final var actual = api.get("/strings").andExpect(status().isOk()).andReturn().getResponse().getContentAsString();
        assertEquals("["protected","strings"]", actual);
    }

    @Test
    @WithJwt("cognito_admin.json")
    void givenUserIsCognitoAdmin_whenGetStrings_thenOk() throws UnsupportedEncodingException, Exception {
        final var actual = api.get("/strings").andExpect(status().isOk()).andReturn().getResponse().getContentAsString();
        assertEquals("["protected","strings"]", actual);
    }

    @Test
    @WithJwt("aad_machin-truc.json")
    void givenUserIsAadMachinTruc_whenGetStrings_thenForbidden() throws UnsupportedEncodingException, Exception {
        api.get("/strings").andExpect(status().isForbidden());
    }

    @Test
    @WithJwt("cognito_machin-truc.json")
    void givenUserIsCognitoMachinTruc_whenGetStrings_thenForbidden() throws UnsupportedEncodingException, Exception {
        api.get("/strings").andExpect(status().isForbidden());
    }

}

利用这一试验资源:

  • aad_admin.json
{
    "sub": "aad-admin",
    "iss": "https://sts.windows.net/0a962d63-6b23-4416-81a6-29f88c553998/",
    "appRoles": [
        {
          "allowedMemberTypes": [
            "User"
          ],
          "description": "msiam_access",
          "displayName": "msiam_access",
          "id": "ef7437e6-4f94-4a0a-a110-a439eb2aa8f7",
          "isEnabled": true,
          "origin": "Application",
          "value": null
        },
        {
          "allowedMemberTypes": [
            "User"
          ],
          "description": "Administrators Only",
          "displayName": "Admin",
          "id": "4f8f8640-f081-492d-97a0-caf24e9bc134",
          "isEnabled": true,
          "origin": "ServicePrincipal",
          "value": "Administrator"
        }
    ],
    "scope": "openid profile machin:truc"
}
  • aad_machin-truc.json
{
    "sub": "aad-user",
    "iss": "https://sts.windows.net/0a962d63-6b23-4416-81a6-29f88c553998/",
    "appRoles": [
        {
          "allowedMemberTypes": [
            "User"
          ],
          "description": "msiam_access",
          "displayName": "msiam_access",
          "id": "ef7437e6-4f94-4a0a-a110-a439eb2aa8f7",
          "isEnabled": true,
          "origin": "Application",
          "value": null
        }
    ],
    "scope": "openid profile machin:truc"
}
  • cognito_admin.json
{
    "sub": "amazon-cognito-admin",
    "iss": "https://cognito-idp.us-west-2.amazonaws.com/us-west-2_RzhmgLwjl",
    "cognito:groups": ["admin", "machin:truc"],
    "scope": "openid profile cog:scope"
}
  • cognito_machin-truc.json
{
    "sub": "amazon-cognito-user",
    "iss": "https://cognito-idp.us-west-2.amazonaws.com/us-west-2_RzhmgLwjl",
    "cognito:groups": ["machin:truc"],
    "scope": "openid profile cog:scope"
}




相关问题
Spring Properties File

Hi have this j2ee web application developed using spring framework. I have a problem with rendering mnessages in nihongo characters from the properties file. I tried converting the file to ascii using ...

Logging a global ID in multiple components

I have a system which contains multiple applications connected together using JMS and Spring Integration. Messages get sent along a chain of applications. [App A] -> [App B] -> [App C] We set a ...

Java Library Size

If I m given two Java Libraries in Jar format, 1 having no bells and whistles, and the other having lots of them that will mostly go unused.... my question is: How will the larger, mostly unused ...

How to get the Array Class for a given Class in Java?

I have a Class variable that holds a certain type and I need to get a variable that holds the corresponding array class. The best I could come up with is this: Class arrayOfFooClass = java.lang....

SQLite , Derby vs file system

I m working on a Java desktop application that reads and writes from/to different files. I think a better solution would be to replace the file system by a SQLite database. How hard is it to migrate ...

热门标签