PasswordGrantAuthenticationManager implements AuthenticationManager, ApplicationEventPublisherAware { private Authentication oidcPasswordGrant(Authentication authentication, OIDCIdentityProviderDefinition config) { URL tokenUrl = config.getTokenUrl(); String clientId = config.getRelyingPartyId(); String clientSecret = config.getRelyingPartySecret(); if (clientId == null || clientSecret == null) { throw new ProviderConfigurationException("External OpenID Connect provider configuration is missing relyingPartyId or relyingPartySecret."); } String userName = authentication.getPrincipal() instanceof String ? (String)authentication.getPrincipal() : null; String password = authentication.getCredentials() instanceof String ? (String)authentication.getCredentials() : null; if (userName == null || password == null) { throw new BadCredentialsException("Request is missing username or password."); } RestTemplate rt; if (config.isSkipSslValidation()) { rt = restTemplateConfig.trustingRestTemplate(); } else { rt = restTemplateConfig.nonTrustingRestTemplate(); } HttpHeaders headers = new HttpHeaders(); headers.setAccept(Collections.singletonList(APPLICATION_JSON)); headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED); String auth = clientId + ":" + clientSecret; headers.add("Authorization","Basic "+Base64Utils.encodeToString(auth.getBytes())); if (config.isSetForwardHeader() && authentication.getDetails() != null &&authentication.getDetails() instanceof UaaAuthenticationDetails) { UaaAuthenticationDetails details = (UaaAuthenticationDetails) authentication.getDetails(); if (details.getOrigin() != null) { headers.add("X-Forwarded-For", details.getOrigin()); } } MultiValueMap<String, String> params = new LinkedMultiValueMap<>(); params.add("grant_type", GRANT_TYPE_PASSWORD); params.add("response_type","id_token"); params.add("username", userName); params.add("password", password); List<Prompt> prompts = config.getPrompts(); List<String> promptsToInclude = new ArrayList<>(); if (prompts != null) { for (Prompt prompt : prompts) { if ("username".equals(prompt.getName()) || "password".equals(prompt.getName()) || "passcode".equals(prompt.getName())) continue; promptsToInclude.add(prompt.getName()); } } if (authentication.getDetails() instanceof UaaAuthenticationDetails) { UaaAuthenticationDetails details = (UaaAuthenticationDetails)authentication.getDetails(); for (String prompt : promptsToInclude) { String[] values = details.getParameterMap().get(prompt); if (values == null || values.length != 1 || !StringUtils.hasText(values[0])) { continue; } params.add(prompt, values[0]); } } HttpEntity<MultiValueMap<String, String>> request = new HttpEntity<>(params, headers); String idToken = null; try { ResponseEntity<Map<String,String>> tokenResponse = rt.exchange(tokenUrl.toString(), HttpMethod.POST, request, new ParameterizedTypeReference<Map<String,String>>(){}); if (tokenResponse.hasBody()) { Map<String, String> body = tokenResponse.getBody(); idToken = body.get("id_token"); } } catch (HttpClientErrorException e) { publish(new IdentityProviderAuthenticationFailureEvent(authentication, userName, OriginKeys.OIDC10, IdentityZoneHolder.getCurrentZoneId())); throw new BadCredentialsException(e.getResponseBodyAsString(), e); } if (idToken == null) { publish(new IdentityProviderAuthenticationFailureEvent(authentication, userName, OriginKeys.OIDC10, IdentityZoneHolder.getCurrentZoneId())); throw new BadCredentialsException("Could not obtain id_token from external OpenID Connect provider."); } ExternalOAuthCodeToken token = new ExternalOAuthCodeToken(null, null, null, idToken, null, null); return externalOAuthAuthenticationManager.authenticate(token); } PasswordGrantAuthenticationManager(DynamicZoneAwareAuthenticationManager zoneAwareAuthzAuthenticationManager, final @Qualifier("identityProviderProvisioning") IdentityProviderProvisioning identityProviderProvisioning, RestTemplateConfig restTemplateConfig, ExternalOAuthAuthenticationManager externalOAuthAuthenticationManager, MultitenantClientServices clientDetailsService, ExternalOAuthProviderConfigurator externalOAuthProviderProvisioning); @Override Authentication authenticate(Authentication authentication); @Override void setApplicationEventPublisher(ApplicationEventPublisher applicationEventPublisher);  }
@Test void testOIDCPasswordGrant() { UaaLoginHint loginHint = mock(UaaLoginHint.class); when(loginHint.getOrigin()).thenReturn("oidcprovider"); Authentication auth = mock(Authentication.class); when(auth.getPrincipal()).thenReturn("marissa"); when(auth.getCredentials()).thenReturn("koala"); when(zoneAwareAuthzAuthenticationManager.extractLoginHint(auth)).thenReturn(loginHint); RestTemplate rt = mock(RestTemplate.class); when(restTemplateConfig.nonTrustingRestTemplate()).thenReturn(rt); ResponseEntity<Map<String,String>> response = mock(ResponseEntity.class); when(response.hasBody()).thenReturn(true); when(response.getBody()).thenReturn(Collections.singletonMap("id_token", "mytoken")); when(rt.exchange(anyString(),any(HttpMethod.class),any(HttpEntity.class),any(ParameterizedTypeReference.class))).thenReturn(response); instance.authenticate(auth); ArgumentCaptor<HttpEntity> httpEntityArgumentCaptor = ArgumentCaptor.forClass(HttpEntity.class); verify(rt, times(1)).exchange(eq("http: ArgumentCaptor<ExternalOAuthCodeToken> tokenArgumentCaptor = ArgumentCaptor.forClass(ExternalOAuthCodeToken.class); verify(externalOAuthAuthenticationManager, times(1)).authenticate(tokenArgumentCaptor.capture()); verify(zoneAwareAuthzAuthenticationManager, times(0)).authenticate(any()); HttpEntity httpEntity = httpEntityArgumentCaptor.getValue(); assertNotNull(httpEntity); assertTrue(httpEntity.hasBody()); assertTrue(httpEntity.getBody() instanceof MultiValueMap); MultiValueMap<String,String> body = (MultiValueMap<String, String>)httpEntity.getBody(); assertEquals(4, body.size()); assertEquals(Collections.singletonList("password"), body.get("grant_type")); assertEquals(Collections.singletonList("id_token"), body.get("response_type")); assertEquals(Collections.singletonList("marissa"), body.get("username")); assertEquals(Collections.singletonList("koala"), body.get("password")); HttpHeaders headers = httpEntity.getHeaders(); assertEquals(Collections.singletonList(APPLICATION_JSON), headers.getAccept()); assertEquals(MediaType.APPLICATION_FORM_URLENCODED, headers.getContentType()); assertNotNull(headers.get("Authorization")); assertEquals(1, headers.get("Authorization").size()); assertThat(headers.get("Authorization").get(0), startsWith("Basic ")); assertNull(headers.get("X-Forwarded-For")); assertEquals("mytoken", tokenArgumentCaptor.getValue().getIdToken()); }