package org.apereo.cas.authentication;
import org.apache.commons.lang3.SerializationUtils;
import org.apache.commons.lang3.builder.ToStringBuilder;
import org.apache.cxf.rt.security.SecurityConstants;
import org.apache.cxf.ws.security.tokenstore.SecurityToken;
import org.apereo.cas.CipherExecutor;
import org.apereo.cas.authentication.metadata.BaseAuthenticationMetadataPopulator;
import org.apereo.cas.authentication.principal.Service;
import org.apereo.cas.services.ServicesManager;
import org.apereo.cas.services.UnauthorizedSsoServiceException;
import org.apereo.cas.util.EncodingUtils;
import org.apereo.cas.ws.idp.WSFederationConstants;
import org.apereo.cas.ws.idp.services.WSFederationRegisteredService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.core.Ordered;
/**
* This is {@link SecurityTokenServiceAuthenticationMetaDataPopulator}.
*
* @author Misagh Moayyed
* @since 5.1.0
*/
public class SecurityTokenServiceAuthenticationMetaDataPopulator extends BaseAuthenticationMetadataPopulator {
private static final Logger LOGGER = LoggerFactory.getLogger(SecurityTokenServiceAuthenticationMetaDataPopulator.class);
private final ServicesManager servicesManager;
private final AuthenticationServiceSelectionStrategy selectionStrategy;
private final CipherExecutor<String, String> credentialCipherExecutor;
private final SecurityTokenServiceClientBuilder clientBuilder;
public SecurityTokenServiceAuthenticationMetaDataPopulator(final ServicesManager servicesManager,
final AuthenticationServiceSelectionStrategy selectionStrategy,
final CipherExecutor<String, String> credentialCipherExecutor,
final SecurityTokenServiceClientBuilder clientBuilder) {
this.servicesManager = servicesManager;
this.selectionStrategy = selectionStrategy;
this.credentialCipherExecutor = credentialCipherExecutor;
this.clientBuilder = clientBuilder;
}
private void invokeSecurityTokenServiceForToken(final AuthenticationTransaction transaction, final AuthenticationBuilder builder,
final WSFederationRegisteredService rp, final SecurityTokenServiceClient sts) {
final UsernamePasswordCredential up = transaction.getCredentials()
.stream()
.filter(UsernamePasswordCredential.class::isInstance)
.map(UsernamePasswordCredential.class::cast)
.findFirst()
.orElse(null);
if (up != null) {
try {
sts.getProperties().put(SecurityConstants.USERNAME, up.getUsername());
final String uid = credentialCipherExecutor.encode(up.getUsername());
sts.getProperties().put(SecurityConstants.PASSWORD, uid);
final SecurityToken token = sts.requestSecurityToken(rp.getAppliesTo());
final String tokenStr = EncodingUtils.encodeBase64(SerializationUtils.serialize(token));
builder.addAttribute(WSFederationConstants.SECURITY_TOKEN_ATTRIBUTE, tokenStr);
} catch (final Exception e) {
throw new AuthenticationException(e.getMessage());
}
}
}
@Override
public int getOrder() {
return Ordered.HIGHEST_PRECEDENCE;
}
@Override
public void populateAttributes(final AuthenticationBuilder builder, final AuthenticationTransaction transaction) {
if (!this.selectionStrategy.supports(transaction.getService())) {
return;
}
final Service service = this.selectionStrategy.resolveServiceFrom(transaction.getService());
if (service != null) {
final WSFederationRegisteredService rp = this.servicesManager.findServiceBy(service, WSFederationRegisteredService.class);
if (rp == null || !rp.getAccessStrategy().isServiceAccessAllowed()) {
LOGGER.warn("Service [{}] is not allowed to use SSO.", rp);
throw new UnauthorizedSsoServiceException();
}
final SecurityTokenServiceClient sts = clientBuilder.buildClientForSecurityTokenRequests(rp);
invokeSecurityTokenServiceForToken(transaction, builder, rp, sts);
}
}
@Override
public boolean supports(final Credential credential) {
return true;
}
@Override
public String toString() {
return new ToStringBuilder(this)
.appendSuper(super.toString())
.toString();
}
}