use of org.apereo.cas.adaptors.duo.DuoSecurityUserAccount in project cas by apereo.
the class BaseDuoSecurityAuthenticationService method getUserAccount.
@Override
public DuoSecurityUserAccount getUserAccount(final String username) {
if (!properties.isAccountStatusEnabled()) {
LOGGER.debug("Checking Duo Security for user's [{}] account status is disabled", username);
val account = new DuoSecurityUserAccount(username);
account.setStatus(DuoSecurityUserAccountStatus.AUTH);
return account;
}
val userAccountCachedMap = userAccountCache.asMap();
if (userAccountCachedMap.containsKey(username)) {
val account = userAccountCachedMap.get(username);
LOGGER.debug("Found cached duo user account [{}]", account);
return account;
}
val account = new DuoSecurityUserAccount(username);
account.setStatus(DuoSecurityUserAccountStatus.AUTH);
try {
val userRequest = buildHttpPostUserPreAuthRequest(username);
signHttpUserPreAuthRequest(userRequest);
LOGGER.debug("Contacting Duo to inquire about username [{}]", username);
val userResponse = getHttpResponse(userRequest);
val jsonResponse = URLDecoder.decode(userResponse, StandardCharsets.UTF_8.name());
LOGGER.debug("Received Duo response [{}]", jsonResponse);
val result = MAPPER.readTree(jsonResponse);
if (!result.has(RESULT_KEY_STAT)) {
LOGGER.warn("Duo response was received in unknown format: [{}]", jsonResponse);
throw new DuoWebException("Invalid response format received from Duo");
}
if (result.get(RESULT_KEY_STAT).asText().equalsIgnoreCase("OK")) {
val response = result.get(RESULT_KEY_RESPONSE);
val authResult = response.get(RESULT_KEY_RESULT).asText().toUpperCase();
val status = DuoSecurityUserAccountStatus.valueOf(authResult);
account.setStatus(status);
account.setMessage(response.get(RESULT_KEY_STATUS_MESSAGE).asText());
if (status == DuoSecurityUserAccountStatus.ENROLL) {
val enrollUrl = response.get(RESULT_KEY_ENROLL_PORTAL_URL).asText();
account.setEnrollPortalUrl(enrollUrl);
}
} else {
val code = result.get(RESULT_KEY_CODE).asInt();
if (code > RESULT_CODE_ERROR_THRESHOLD) {
LOGGER.warn("Duo returned a failure response with code: [{}]. Duo will be considered unavailable", result.get(RESULT_KEY_MESSAGE));
throw new DuoWebException("Duo returned code 500: " + result.get(RESULT_KEY_MESSAGE));
}
LOGGER.warn("Duo returned an Invalid response with message [{}] and detail [{}] " + "when determining user account. This maybe a configuration error in the admin request and Duo will " + "still be considered available.", result.hasNonNull(RESULT_KEY_MESSAGE) ? result.get(RESULT_KEY_MESSAGE).asText() : StringUtils.EMPTY, result.hasNonNull(RESULT_KEY_MESSAGE_DETAIL) ? result.get(RESULT_KEY_MESSAGE_DETAIL).asText() : StringUtils.EMPTY);
}
} catch (final Exception e) {
LOGGER.warn("Reaching Duo has failed with error: [{}]", e.getMessage(), e);
account.setStatus(DuoSecurityUserAccountStatus.UNAVAILABLE);
}
userAccountCachedMap.put(account.getUsername(), account);
LOGGER.debug("Fetched and cached duo user account [{}]", account);
return account;
}
use of org.apereo.cas.adaptors.duo.DuoSecurityUserAccount in project cas by apereo.
the class DuoSecurityAdminApiEndpoint method getUser.
/**
* Fetch duo user account from admin api.
*
* @param username the username
* @param providerId the provider id
* @return the map
*/
@GetMapping(path = "/{username}", produces = MediaType.APPLICATION_JSON_VALUE)
@Operation(summary = "Fetch Duo Security user account from Duo Admin API", parameters = { @Parameter(name = "username", required = true, in = ParameterIn.PATH), @Parameter(name = "providerId") })
public Map<String, DuoSecurityUserAccount> getUser(@PathVariable("username") final String username, @RequestParam(required = false) final String providerId) {
val results = new LinkedHashMap<String, DuoSecurityUserAccount>();
val providers = applicationContext.getBeansOfType(DuoSecurityMultifactorAuthenticationProvider.class).values();
providers.stream().filter(Objects::nonNull).map(DuoSecurityMultifactorAuthenticationProvider.class::cast).filter(provider -> StringUtils.isBlank(providerId) || provider.matches(providerId)).filter(provider -> provider.getDuoAuthenticationService().getAdminApiService().isPresent()).forEach(Unchecked.consumer(p -> {
val duoService = p.getDuoAuthenticationService().getAdminApiService().get();
duoService.getDuoSecurityUserAccount(username).ifPresent(user -> results.put(p.getId(), user));
}));
return results;
}
use of org.apereo.cas.adaptors.duo.DuoSecurityUserAccount in project cas by apereo.
the class DuoSecurityAdminApiEndpoint method createBypassCodes.
/**
* Create bypass codes.
*
* @param username the username
* @param providerId the provider id
* @param userId the user id
* @return the map
*/
@Operation(summary = "Create bypass codes using Duo Admin API", parameters = { @Parameter(name = "username", required = true), @Parameter(name = "providerId"), @Parameter(name = "userId") })
@PostMapping(path = "/bypassCodes", consumes = MediaType.APPLICATION_JSON_VALUE, produces = MediaType.APPLICATION_JSON_VALUE)
public Map<String, List<Long>> createBypassCodes(@RequestParam(value = "username", required = false) final String username, @RequestParam(value = "providerId", required = false) final String providerId, @RequestParam(value = "userId", required = false) final String userId) {
val results = new LinkedHashMap<String, List<Long>>();
val providers = applicationContext.getBeansOfType(DuoSecurityMultifactorAuthenticationProvider.class).values();
providers.stream().filter(Objects::nonNull).map(DuoSecurityMultifactorAuthenticationProvider.class::cast).filter(provider -> StringUtils.isBlank(providerId) || provider.matches(providerId)).filter(provider -> provider.getDuoAuthenticationService().getAdminApiService().isPresent()).forEach(Unchecked.consumer(p -> {
val duoService = p.getDuoAuthenticationService().getAdminApiService().get();
val uid = StringUtils.isBlank(userId) ? duoService.getDuoSecurityUserAccount(username).map(DuoSecurityUserAccount::getUserId).orElse(StringUtils.EMPTY) : userId;
if (StringUtils.isNotBlank(uid)) {
val codes = duoService.createDuoSecurityBypassCodesFor(uid);
results.put(p.getId(), codes);
}
}));
return results;
}
use of org.apereo.cas.adaptors.duo.DuoSecurityUserAccount in project cas by apereo.
the class DefaultDuoSecurityAdminApiService method mapDuoSecurityUserAccount.
private static DuoSecurityUserAccount mapDuoSecurityUserAccount(final JSONObject userJson) throws JSONException {
val user = new DuoSecurityUserAccount(userJson.getString("username"));
user.setStatus(DuoSecurityUserAccountStatus.from(userJson.getString("status")));
FunctionUtils.doIfNotNull(userJson.get("email"), value -> user.addAttribute("email", value.toString()));
FunctionUtils.doIfNotNull(userJson.getString("user_id"), value -> user.addAttribute("user_id", value));
FunctionUtils.doIfNotNull(userJson.get("firstname"), value -> user.addAttribute("firstname", value.toString()));
FunctionUtils.doIfNotNull(userJson.get("lastname"), value -> user.addAttribute("lastname", value.toString()));
FunctionUtils.doIfNotNull(userJson.get("realname"), value -> user.addAttribute("realname", value.toString()));
FunctionUtils.doIfNotNull(userJson.getBoolean("is_enrolled"), value -> user.addAttribute("is_enrolled", value.toString()));
FunctionUtils.doIfNotNull(userJson.getLong("last_login"), value -> user.addAttribute("last_login", value.toString()));
FunctionUtils.doIfNotNull(userJson.getLong("created"), value -> user.addAttribute("created", value.toString()));
FunctionUtils.doIfNotNull(userJson.optString("alias1"), value -> user.addAttribute("alias1", value));
FunctionUtils.doIfNotNull(userJson.optString("alias2"), value -> user.addAttribute("alias2", value));
if (user.getStatus() != DuoSecurityUserAccountStatus.DENY && !user.isEnrolled()) {
user.setStatus(DuoSecurityUserAccountStatus.ENROLL);
}
mapUserPhones(userJson, user);
mapUserGroups(userJson, user);
return user;
}
use of org.apereo.cas.adaptors.duo.DuoSecurityUserAccount in project cas by apereo.
the class DuoSecurityDetermineUserAccountActionTests method verifyOperation.
@SneakyThrows
private static void verifyOperation(final DuoSecurityUserAccountStatus status, final String eventId) {
val context = new MockRequestContext();
val request = new MockHttpServletRequest();
val response = new MockHttpServletResponse();
context.setExternalContext(new ServletExternalContext(new MockServletContext(), request, response));
WebUtils.putServiceIntoFlowScope(context, CoreAuthenticationTestUtils.getWebApplicationService());
val authentication = CoreAuthenticationTestUtils.getAuthentication();
WebUtils.putAuthentication(authentication, context);
val account = new DuoSecurityUserAccount(authentication.getPrincipal().getId());
account.setStatus(status);
account.setEnrollPortalUrl("https://example.org");
val duoService = mock(DuoSecurityAuthenticationService.class);
when(duoService.getUserAccount(anyString())).thenReturn(account);
val provider = mock(DuoSecurityMultifactorAuthenticationProvider.class);
when(provider.getId()).thenReturn(DuoSecurityMultifactorAuthenticationProperties.DEFAULT_IDENTIFIER);
when(provider.getDuoAuthenticationService()).thenReturn(duoService);
when(provider.getRegistrationUrl()).thenReturn("https://registration.duo.com");
when(provider.matches(anyString())).thenReturn(Boolean.TRUE);
val applicationContext = new StaticApplicationContext();
applicationContext.refresh();
ApplicationContextProvider.holdApplicationContext(applicationContext);
ApplicationContextProvider.registerBeanIntoApplicationContext(applicationContext, MultifactorAuthenticationPrincipalResolver.identical(), UUID.randomUUID().toString());
WebUtils.putMultifactorAuthenticationProviderIdIntoFlowScope(context, provider);
TestMultifactorAuthenticationProvider.registerProviderIntoApplicationContext(applicationContext, provider);
val action = new DuoSecurityDetermineUserAccountAction();
val event = action.execute(context);
assertEquals(eventId, event.getId());
}
Aggregations