Generator-jhipster: TestCase error when generating microservice project with oauth2 authentication type

Created on 14 Apr 2018  路  12Comments  路  Source: jhipster/generator-jhipster

Overview of the issue

TestCase error when generating microservice project with oauth2 authentication type

Motivation for or Use Case


When running jhpack on new generated project,can't pass the test.

Reproduce the error

Related issues


TestCase error when using ODIC.See below:
[ERROR] Failures:
[ERROR] AccountResourceIntTest.testGetExistingAccount:116 Status expected:<200> but was:<500>
[INFO]
[ERROR] Tests run: 95, Failures: 1, Errors: 0, Skipped: 0

Suggest a Fix
JHipster Version(s)


5.0.[email protected]

JHipster configuration



.yo-rc.json file

{
  "generator-jhipster": {
    "promptValues": {
      "packageName": "com.gzs.audit",
      "nativeLanguage": "zh-cn"
    },
    "jhipsterVersion": "5.0.0-beta.0",
    "baseName": "onlineshop",
    "reactive": false,
    "packageName": "com.gzs.audit",
    "packageFolder": "com/gzs/audit",
    "serverPort": "8081",
    "authenticationType": "oauth2",
    "cacheProvider": "hazelcast",
    "enableHibernateCache": true,
    "websocket": false,
    "databaseType": "sql",
    "devDatabaseType": "h2Disk",
    "prodDatabaseType": "mysql",
    "searchEngine": false,
    "messageBroker": false,
    "serviceDiscoveryType": "eureka",
    "buildTool": "maven",
    "enableSwaggerCodegen": true,
    "jwtSecretKey": "replaced-by-jhipster-info",
    "enableTranslation": true,
    "applicationType": "microservice",
    "testFrameworks": [],
    "jhiPrefix": "jhi",
    "nativeLanguage": "zh-cn",
    "languages": [
      "zh-cn"
    ],
    "clientPackageManager": "yarn",
    "skipClient": true,
    "skipUserManagement": true
  }
}

Entity configuration(s) entityName.json files generated in the .jhipster directory


simple-online-shop.jh.zip

Browsers and Operating System


macos 10.13.4
[-] Checking this box is mandatory (this is just to show you read everything)

area

Most helpful comment

There's nothing in spring-security-test that allows you to auto-send a Bearer token in an Authorization header is there?

No there isn't. However, we plan on adding oauth test support in Spring Security 5.x

All 12 comments

@tianlinzx +1

I'm looking into this now...

This seems to happen because the Principal is not populated when testing in a microservices environment.

public UserDTO getAccount(Principal principal) { ... }

This same code exists in a monolith and it works. My suspicion is there's something in the microservices security configuration that intercepts the Principal set in the test and nullifies it.

FWIW, if I change MicroserviceSecurityConfiguration from having @EnableResourceServer to having @EnableOAuth2Sso (like a monolith has), the test passes.

@jgrandja Any idea why the following test works fine when using @EnableOAuth2Sso, but not with @EnableResourceServer? For context, we have this test in both a monolith environment (that uses EnableOAuth2Sso) and a microservices environment (that uses EnableResourceServer).

You can see the configuration classes for each in the JHipster project on GitHub:

@Test
@Transactional
public void testGetExistingAccount() throws Exception {
    Set<Authority> authorities = new HashSet<>();
    Authority authority = new Authority();
    authority.setName(AuthoritiesConstants.ADMIN);
    authorities.add(authority);

    User user = new User();
    user.setId(RandomStringUtils.randomAlphanumeric(50));
    user.setLogin("test");
    user.setFirstName("john");
    user.setLastName("doe");
    user.setEmail("[email protected]");
    user.setImageUrl("http://placehold.it/50x50");
    user.setLangKey("en");
    user.setAuthorities(authorities);
    userRepository.save(user);

    // create security-aware mockMvc
    restUserMockMvc = MockMvcBuilders
        .webAppContextSetup(context)
        .apply(springSecurity())
        .build();

    restUserMockMvc.perform(get("/api/account")
        .with(user(user.getLogin()).roles("ADMIN"))
        .accept(MediaType.APPLICATION_JSON))
        .andExpect(status().isOk())
        .andExpect(content().contentType(MediaType.APPLICATION_JSON_UTF8_VALUE))
        .andExpect(jsonPath("$.login").value("test"))
        .andExpect(jsonPath("$.firstName").value("john"))
        .andExpect(jsonPath("$.lastName").value("doe"))
        .andExpect(jsonPath("$.email").value("[email protected]"))
        .andExpect(jsonPath("$.imageUrl").value("http://placehold.it/50x50"))
        .andExpect(jsonPath("$.langKey").value("en"))
        .andExpect(jsonPath("$.authorities").value(AuthoritiesConstants.ADMIN));
}

The method this test hits is as follows:

/**
 * GET  /account : get the current user.
 *
 * @param principal the current user; resolves to null if not authenticated
 * @return the current user
 * @throws InternalServerErrorException 500 (Internal Server Error) if the user couldn't be returned
 */
@GetMapping("/account")
@Timed
@SuppressWarnings("unchecked")
public UserDTO getAccount(Principal principal) {
    if (principal != null) {
        if (principal instanceof OAuth2Authentication) {
            return userService.getUserFromAuthentication((OAuth2Authentication) principal);
        } else {
            // Allow Spring Security Test to be used to mock users in the database
            return userService.getUserWithAuthorities()
                .map(UserDTO::new)
                .orElseThrow(() -> new InternalServerErrorException("User could not be found"));
        }
    } else {
        throw new InternalServerErrorException("User could not be found");
    }
}

In a microservices environment, the Principal is null. Thanks in advance for any advice!

Edit: You can reproduce this issue using the following commands:

git clone https://github.com/mraible/jhipster5-ms-user.git
cd jhipster5-ms-user/blog
./mvnw test

I'm not sure AccountResource and AccountResourceIntTest should exist when applicationType === 'microservice' because account.service.ts only exists on the gateway. I'll make a PR to remove it.

@mraible If you could put together a minimal sample the reproduces the issue that would be more efficient on my end. I will say that @EnableOAuth2Sso can be tricky at times as it applies a number of conditional checks on properties rooted at security.oauth2.resource.*.

Are you able to use @EnableResourceServer exclusively?

@jgrandja It's probably something in JHipster's configuration that causes this, so I'm not sure a minimal sample would help. I think these steps are pretty simple though! ;)

git clone https://github.com/mraible/jhipster5-ms-user.git
cd jhipster5-ms-user/blog
./mvnw test -Dtest=AccountResourceIntTest

The test will fail:

[ERROR] Failures:
[ERROR]   AccountResourceIntTest.testGetExistingAccount:127 Status expected:<200> but was:<500>

Change from @EnableResourceServer to @EnableOAuth2Sso in blog/src/main/java/com/okta/developer/blog/config/MicroserviceSecurityConfiguration.java and it passes.

@mraible The reason @EnableResourceServer results in a null Principal in getAccount(Principal principal) is because of the configured RequestMatcher in MicroserviceSecurityConfiguration:

            .requestMatcher(authorizationHeaderRequestMatcher())
               .authorizeRequests()
                 .antMatchers("/api/profile-info").permitAll()
                .antMatchers("/api/**").authenticated()

The RequestHeaderRequestMatcher("Authorization") is configured but the request in the test does not set the Authorization header which results in no matching FilterChain. So the request passes through without going through any of the Spring Security filters and therefore the Authentication doesn't get resolved.

However, even if you comment out .requestMatcher(authorizationHeaderRequestMatcher()) which will match on a FilterChain (AnyRequestMatcher) a 401 error will occur. So other things will need to be changed in that test to make it pass.

@jgrandja I suspected that might be the case. There's nothing in spring-security-test that allows you to auto-send a Bearer token in an Authorization header is there? I was hoping @WithMockUser or .with(user(user.getLogin()).roles("ADMIN")) could do that somehow.

There's nothing in spring-security-test that allows you to auto-send a Bearer token in an Authorization header is there?

No there isn't. However, we plan on adding oauth test support in Spring Security 5.x

Was this page helpful?
0 / 5 - 0 ratings

Related issues

DanielFran picture DanielFran  路  3Comments

marcelinobadin picture marcelinobadin  路  3Comments

SudharakaP picture SudharakaP  路  3Comments

RizziCR picture RizziCR  路  3Comments

trajakovic picture trajakovic  路  4Comments