package org.cagrid.dorian.service.core;
import gov.nih.nci.cagrid.opensaml.SAMLAssertion;
import java.io.IOException;
import java.rmi.RemoteException;
import java.security.PublicKey;
import java.security.cert.X509Certificate;
import java.util.Arrays;
import java.util.List;
import javax.xml.bind.JAXBException;
import javax.xml.namespace.QName;
import org.apache.commons.lang.StringUtils;
import org.cagrid.core.common.FaultHelper;
import org.cagrid.core.common.JAXBUtils;
import org.cagrid.dorian.common.AuditConstants;
import org.cagrid.dorian.common.SAMLConstants;
import org.cagrid.dorian.model.exceptions.DorianInternalException;
import org.cagrid.dorian.model.exceptions.InvalidAssertionException;
import org.cagrid.dorian.model.exceptions.InvalidHostCertificateException;
import org.cagrid.dorian.model.exceptions.InvalidHostCertificateRequestException;
import org.cagrid.dorian.model.exceptions.InvalidTrustedIdPException;
import org.cagrid.dorian.model.exceptions.InvalidUserCertificateException;
import org.cagrid.dorian.model.exceptions.InvalidUserException;
import org.cagrid.dorian.model.exceptions.InvalidUserPropertyException;
import org.cagrid.dorian.model.exceptions.NoSuchUserException;
import org.cagrid.dorian.model.exceptions.PermissionDeniedException;
import org.cagrid.dorian.model.exceptions.UserPolicyException;
import org.cagrid.dorian.model.federation.CertificateLifetime;
import org.cagrid.dorian.model.federation.FederationAuditFilter;
import org.cagrid.dorian.model.federation.FederationAuditRecord;
import org.cagrid.dorian.model.federation.GridUser;
import org.cagrid.dorian.model.federation.GridUserFilter;
import org.cagrid.dorian.model.federation.GridUserPolicy;
import org.cagrid.dorian.model.federation.GridUserRecord;
import org.cagrid.dorian.model.federation.GridUserSearchCriteria;
import org.cagrid.dorian.model.federation.GridUserStatus;
import org.cagrid.dorian.model.federation.HostCertificateFilter;
import org.cagrid.dorian.model.federation.HostCertificateRecord;
import org.cagrid.dorian.model.federation.HostCertificateRequest;
import org.cagrid.dorian.model.federation.HostCertificateUpdate;
import org.cagrid.dorian.model.federation.HostRecord;
import org.cagrid.dorian.model.federation.HostSearchCriteria;
import org.cagrid.dorian.model.federation.SAMLAttributeDescriptor;
import org.cagrid.dorian.model.federation.SAMLAuthenticationMethod;
import org.cagrid.dorian.model.federation.TrustedIdP;
import org.cagrid.dorian.model.federation.TrustedIdPStatus;
import org.cagrid.dorian.model.federation.TrustedIdentityProviders;
import org.cagrid.dorian.model.federation.UserCertificateFilter;
import org.cagrid.dorian.model.federation.UserCertificateRecord;
import org.cagrid.dorian.model.federation.UserCertificateUpdate;
import org.cagrid.dorian.model.idp.AccountProfile;
import org.cagrid.dorian.model.idp.Application;
import org.cagrid.dorian.model.idp.IdentityProviderAudit;
import org.cagrid.dorian.model.idp.IdentityProviderAuditFilter;
import org.cagrid.dorian.model.idp.IdentityProviderAuditRecord;
import org.cagrid.dorian.model.idp.LocalUser;
import org.cagrid.dorian.model.idp.LocalUserFilter;
import org.cagrid.dorian.policy.DorianPolicy;
import org.cagrid.dorian.service.CertificateSignatureAlgorithm;
import org.cagrid.dorian.service.Dorian;
import org.cagrid.dorian.service.PropertyManager;
import org.cagrid.dorian.service.ca.CertificateAuthorityManager;
import org.cagrid.dorian.service.federation.AutoApprovalPolicy;
import org.cagrid.dorian.service.federation.FederationDefaults;
import org.cagrid.dorian.service.federation.IdentityFederationManager;
import org.cagrid.dorian.service.federation.IdentityFederationProperties;
import org.cagrid.dorian.service.idp.IdentityProvider;
import org.cagrid.dorian.service.idp.UserManager;
import org.cagrid.gaards.authentication.AuthenticationProfiles;
import org.cagrid.gaards.authentication.BasicAuthentication;
import org.cagrid.gaards.authentication.Credential;
import org.cagrid.gaards.authentication.faults.AuthenticationProviderException;
import org.cagrid.gaards.authentication.faults.CredentialNotSupportedException;
import org.cagrid.gaards.authentication.faults.InvalidCredentialException;
import org.cagrid.gaards.pki.CertUtil;
import org.cagrid.tools.database.Database;
import org.cagrid.tools.database.DatabaseException;
import org.cagrid.tools.events.EventManager;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class DorianImpl implements Dorian {
public static final String IDP_ADMIN_USER_ID = "dorian";
public static final String IDP_ADMIN_PASSWORD = "DorianAdmin$1";
private final static Logger log = LoggerFactory.getLogger(DorianImpl.class);
private final DorianProperties dorianProperties;
private EventManager eventManager;
private Database db;
private PropertyManager propertyManager;
private CertificateAuthorityManager caManager;
private IdentityProvider identityProvider;
private IdentityFederationProperties ifsConfiguration;
private IdentityFederationManager ifm;
public DorianImpl(DorianProperties dorianProperties) {
this.dorianProperties = dorianProperties;
}
public Database getDatabase() {
return this.db;
}
@Override
public X509Certificate getCACertificate() throws DorianInternalException {
try {
return caManager.getDefaultCertificateAuthority().getCACertificate();
} catch (Exception e) {
log.error(e.getMessage(), e);
DorianInternalException fault = FaultHelper.createFaultException(DorianInternalException.class, "An unexpected error occurred, in obtaining the CA certificate.");
FaultHelper.addMessage(fault, e.getMessage());
throw fault;
}
}
@Override
public X509Certificate getIdPCertificate() throws DorianInternalException {
return identityProvider.getIdPCertificate();
}
@Override
public void changeLocalUserPassword(BasicAuthentication credential, String newPassword) throws DorianInternalException, PermissionDeniedException, InvalidUserPropertyException {
identityProvider.changePassword(credential, newPassword);
}
@Override
public LocalUser[] findLocalUsers(String gridIdentity, LocalUserFilter filter) throws DorianInternalException, PermissionDeniedException {
String uid = null;
try {
uid = ifm.getUserIdVerifyTrustedIdP(identityProvider.getIdPCertificate(), gridIdentity);
} catch (Exception e) {
String message = "Permission to find local users was denied, caller is not a valid user.";
eventManager.logEvent(gridIdentity, AuditConstants.SYSTEM_ID, IdentityProviderAudit.LOCAL_ACCESS_DENIED.value(), message);
PermissionDeniedException fault = FaultHelper.createFaultException(PermissionDeniedException.class, message);
throw fault;
}
return this.identityProvider.findUsers(uid, filter);
}
@Override
public void updateLocalUser(String gridIdentity, LocalUser u) throws DorianInternalException, PermissionDeniedException, NoSuchUserException, InvalidUserPropertyException {
String uid = null;
try {
uid = ifm.getUserIdVerifyTrustedIdP(identityProvider.getIdPCertificate(), gridIdentity);
} catch (Exception e) {
String message = "Permission to update a user was denied, caller is not a valid user.";
this.eventManager.logEvent(gridIdentity, AuditConstants.SYSTEM_ID, IdentityProviderAudit.LOCAL_ACCESS_DENIED.value(), message);
PermissionDeniedException fault = FaultHelper.createFaultException(PermissionDeniedException.class, message);
throw fault;
}
this.identityProvider.updateUser(uid, u);
}
@Override
public void removeLocalUser(String gridIdentity, String userId) throws DorianInternalException, PermissionDeniedException {
String uid = null;
try {
uid = ifm.getUserIdVerifyTrustedIdP(identityProvider.getIdPCertificate(), gridIdentity);
} catch (Exception e) {
String message = "Permission to remove a user was denied, caller is not a valid user.";
this.eventManager.logEvent(gridIdentity, AuditConstants.SYSTEM_ID, IdentityProviderAudit.LOCAL_ACCESS_DENIED.value(), message);
PermissionDeniedException fault = FaultHelper.createFaultException(PermissionDeniedException.class, message);
throw fault;
}
this.identityProvider.removeUser(uid, userId);
this.ifm.removeUserByLocalIdIfExists(identityProvider.getIdPCertificate(), userId);
}
@Override
public List<IdentityProviderAuditRecord> performIdentityProviderAudit(String gridIdentity, IdentityProviderAuditFilter f) throws DorianInternalException, PermissionDeniedException {
String uid = null;
try {
uid = ifm.getUserIdVerifyTrustedIdP(identityProvider.getIdPCertificate(), gridIdentity);
} catch (Exception e) {
String message = "Permission to perform an audit was denied, caller is not a valid user.";
this.eventManager.logEvent(gridIdentity, AuditConstants.SYSTEM_ID, IdentityProviderAudit.LOCAL_ACCESS_DENIED.value(), message);
PermissionDeniedException fault = FaultHelper.createFaultException(PermissionDeniedException.class, message);
throw fault;
}
return this.identityProvider.performAudit(uid, f);
}
@Override
public SAMLAssertion authenticate(Credential credential) throws AuthenticationProviderException, InvalidCredentialException, CredentialNotSupportedException {
return identityProvider.authenticate(credential);
}
@Override
public String registerLocalUser(Application a) throws DorianInternalException, InvalidUserPropertyException {
return this.identityProvider.register(a);
}
@Override
public GridUserPolicy[] getGridUserPolicies(String callerGridIdentity) throws DorianInternalException, PermissionDeniedException {
return ifm.getUserPolicies(callerGridIdentity);
}
@Override
public X509Certificate requestUserCertificate(gov.nih.nci.cagrid.opensaml.SAMLAssertion saml, PublicKey publicKey, CertificateLifetime lifetime, CertificateSignatureAlgorithm sa)
throws DorianInternalException, InvalidAssertionException, UserPolicyException, PermissionDeniedException {
return ifm.requestUserCertificate(saml, publicKey, lifetime, sa);
}
@Override
public TrustedIdP[] getTrustedIdPs(String callerGridIdentity) throws DorianInternalException, PermissionDeniedException {
return ifm.getTrustedIdPs(callerGridIdentity);
}
@Override
public TrustedIdP addTrustedIdP(String callerGridIdentity, TrustedIdP idp) throws DorianInternalException, InvalidTrustedIdPException, PermissionDeniedException {
return ifm.addTrustedIdP(callerGridIdentity, idp);
}
@Override
public void updateTrustedIdP(String callerGridIdentity, TrustedIdP idp) throws DorianInternalException, InvalidTrustedIdPException, PermissionDeniedException {
ifm.updateTrustedIdP(callerGridIdentity, idp);
}
@Override
public void removeTrustedIdP(String callerGridIdentity, TrustedIdP idp) throws DorianInternalException, InvalidTrustedIdPException, PermissionDeniedException {
ifm.removeTrustedIdP(callerGridIdentity, idp.getId());
}
@Override
public GridUser[] findGridUsers(String callerGridIdentity, GridUserFilter filter) throws DorianInternalException, PermissionDeniedException {
return ifm.findUsers(callerGridIdentity, filter);
}
@Override
public void updateGridUser(String callerGridIdentity, GridUser usr) throws DorianInternalException, InvalidUserException, PermissionDeniedException {
ifm.updateUser(callerGridIdentity, usr);
}
@Override
public void removeGridUser(String callerGridIdentity, GridUser user) throws DorianInternalException, InvalidUserException, PermissionDeniedException {
ifm.removeUser(callerGridIdentity, user);
}
@Override
public void addAdmin(String callerGridIdentity, String gridIdentity) throws RemoteException, DorianInternalException, PermissionDeniedException {
ifm.addAdmin(callerGridIdentity, gridIdentity);
}
@Override
public void removeAdmin(String callerGridIdentity, String gridIdentity) throws RemoteException, DorianInternalException, PermissionDeniedException {
ifm.removeAdmin(callerGridIdentity, gridIdentity);
}
@Override
public String[] getAdmins(String callerGridIdentity) throws RemoteException, DorianInternalException, PermissionDeniedException {
return ifm.getAdmins(callerGridIdentity);
}
@Override
public HostCertificateRecord requestHostCertificate(String callerGridId, HostCertificateRequest req, CertificateSignatureAlgorithm alg) throws DorianInternalException,
InvalidHostCertificateRequestException, InvalidHostCertificateException, PermissionDeniedException {
return ifm.requestHostCertificate(callerGridId, req, alg);
}
@Override
public HostCertificateRecord[] getOwnedHostCertificates(String callerGridId) throws DorianInternalException, PermissionDeniedException {
return ifm.getHostCertificatesForCaller(callerGridId);
}
@Override
public HostCertificateRecord approveHostCertificate(String callerGridId, long recordId, CertificateSignatureAlgorithm alg) throws DorianInternalException, InvalidHostCertificateException,
PermissionDeniedException {
return ifm.approveHostCertificate(callerGridId, recordId, alg);
}
@Override
public HostCertificateRecord[] findHostCertificates(String callerGridId, HostCertificateFilter hostCertificateFilter) throws DorianInternalException, PermissionDeniedException {
return ifm.findHostCertificates(callerGridId, hostCertificateFilter);
}
@Override
public void updateHostCertificateRecord(String callerGridId, HostCertificateUpdate update) throws DorianInternalException, InvalidHostCertificateException, PermissionDeniedException {
ifm.updateHostCertificateRecord(callerGridId, update);
}
@Override
public HostCertificateRecord renewHostCertificate(String callerGridId, long recordId, CertificateSignatureAlgorithm algorithm) throws DorianInternalException, InvalidHostCertificateException, PermissionDeniedException {
return ifm.renewHostCertificate(callerGridId, recordId, algorithm);
}
@Override
public boolean doesLocalUserExist(String userId) throws DorianInternalException {
return identityProvider.doesUserExist(userId);
}
@Override
public void clearDatabase() throws DorianInternalException {
try {
this.identityProvider.clearDatabase();
} catch (Exception e) {
log.error(e.getMessage(), e);
}
try {
this.ifm.clearDatabase();
} catch (Exception e) {
log.error(e.getMessage(), e);
}
try {
propertyManager.clearDatabase();
} catch (Exception e) {
log.error(e.getMessage(), e);
}
}
@Override
public TrustedIdentityProviders getTrustedIdentityProviders() throws DorianInternalException {
return ifm.getTrustedIdentityProviders();
}
@Override
public List<UserCertificateRecord> findUserCertificateRecords(String callerIdentity, UserCertificateFilter f) throws DorianInternalException, InvalidUserCertificateException,
PermissionDeniedException {
return ifm.findUserCertificateRecords(callerIdentity, f);
}
@Override
public void updateUserCertificateRecord(String callerIdentity, UserCertificateUpdate update) throws DorianInternalException, InvalidUserCertificateException, PermissionDeniedException {
ifm.updateUserCertificateRecord(callerIdentity, update);
}
@Override
public void removeUserCertificate(String callerIdentity, long serialNumber) throws DorianInternalException, InvalidUserCertificateException, PermissionDeniedException {
ifm.removeUserCertificate(callerIdentity, serialNumber);
}
@Override
public List<FederationAuditRecord> performFederationAudit(String callerIdentity, FederationAuditFilter f) throws DorianInternalException, PermissionDeniedException {
return ifm.performAudit(callerIdentity, f);
}
@Override
public List<GridUserRecord> userSearch(String callerIdentity, GridUserSearchCriteria criteria) throws RemoteException, DorianInternalException, PermissionDeniedException {
return ifm.userSearch(callerIdentity, criteria);
}
@Override
public List<HostRecord> hostSearch(String callerIdentity, HostSearchCriteria criteria) throws RemoteException, DorianInternalException, PermissionDeniedException {
return ifm.hostSearch(callerIdentity, criteria);
}
@Override
public AccountProfile getAccountProfile(String gridIdentity) throws RemoteException, DorianInternalException, PermissionDeniedException {
String uid = null;
try {
uid = ifm.getUserIdVerifyTrustedIdP(identityProvider.getIdPCertificate(), gridIdentity);
} catch (Exception e) {
String message = "Permission to get the account profile for the user was denied, caller is not a valid user.";
eventManager.logEvent(gridIdentity, AuditConstants.SYSTEM_ID, IdentityProviderAudit.LOCAL_ACCESS_DENIED.value(), message);
PermissionDeniedException fault = FaultHelper.createFaultException(PermissionDeniedException.class, message);
throw fault;
}
return this.identityProvider.getAccountProfile(uid);
}
@Override
public void updateAccountProfile(String gridIdentity, AccountProfile profile) throws RemoteException, DorianInternalException, InvalidUserPropertyException, PermissionDeniedException,
NoSuchUserException {
String uid = null;
try {
uid = ifm.getUserIdVerifyTrustedIdP(identityProvider.getIdPCertificate(), gridIdentity);
} catch (Exception e) {
String message = "Permission to update the account profile for the user was denied, caller is not a valid user.";
eventManager.logEvent(gridIdentity, AuditConstants.SYSTEM_ID, IdentityProviderAudit.LOCAL_ACCESS_DENIED.value(), message);
PermissionDeniedException fault = FaultHelper.createFaultException(PermissionDeniedException.class, message);
throw fault;
}
this.identityProvider.updateAccountProfile(uid, profile);
}
@Override
public DorianPolicy getDorianPolicy() {
DorianPolicy p = new DorianPolicy();
p.setIdentityProviderPolicy(identityProvider.getPolicy());
p.setFederationPolicy(ifm.getFederationPolicy());
return p;
}
@Override
public void setPublish(String callerGridIdentity, TrustedIdP idp, boolean publish) throws DorianInternalException, InvalidTrustedIdPException, PermissionDeniedException {
ifm.setPublish(callerGridIdentity, idp, publish);
}
@Override
public boolean getPublish(String callerGridIdentity, TrustedIdP idp) throws DorianInternalException, InvalidTrustedIdPException, PermissionDeniedException {
return ifm.getPublish(callerGridIdentity, idp);
}
@Override
public AuthenticationProfiles getAuthenticationProfiles() {
AuthenticationProfiles authProfiles = new AuthenticationProfiles();
QName basicAuthenticationQName = JAXBUtils.getQName(BasicAuthentication.class);
authProfiles.getProfile().add(basicAuthenticationQName);
return authProfiles;
}
public void initialize() throws JAXBException, DatabaseException, DorianInternalException, IOException {
eventManager = dorianProperties.getEventManager();
UserManager.ADMIN_USER_ID = IDP_ADMIN_USER_ID;
UserManager.ADMIN_PASSWORD = IDP_ADMIN_PASSWORD;
db = dorianProperties.getDatabase();
db.createDatabaseIfNeeded();
propertyManager = new PropertyManager(db);
this.caManager = dorianProperties.getCertificateAuthorityManager();
identityProvider = new IdentityProvider(dorianProperties.getIdentityProviderProperties(), db, this.caManager.getDefaultCertificateAuthority(), eventManager);
TrustedIdP idp = new TrustedIdP();
idp.setName(dorianProperties.getIdentityProviderProperties().getName());
idp.setDisplayName(dorianProperties.getIdentityProviderProperties().getName());
SAMLAuthenticationMethod[] methods = new SAMLAuthenticationMethod[1];
methods[0] = SAMLAuthenticationMethod.fromValue("urn:oasis:names:tc:SAML:1.0:am:password");
idp.getAuthenticationMethod().addAll(Arrays.asList(methods));
idp.setUserPolicyClass(AutoApprovalPolicy.class.getName());
idp.setIdPCertificate(CertUtil.writeCertificate(identityProvider.getIdPCertificate()));
idp.setStatus(TrustedIdPStatus.ACTIVE);
// TODO
final String serviceId = "https://localhost";
idp.setAuthenticationServiceURL(serviceId);
SAMLAttributeDescriptor uid = new SAMLAttributeDescriptor();
uid.setNamespaceURI(SAMLConstants.UID_ATTRIBUTE_NAMESPACE);
uid.setName(SAMLConstants.UID_ATTRIBUTE);
idp.setUserIdAttributeDescriptor(uid);
SAMLAttributeDescriptor firstName = new SAMLAttributeDescriptor();
firstName.setNamespaceURI(SAMLConstants.FIRST_NAME_ATTRIBUTE_NAMESPACE);
firstName.setName(SAMLConstants.FIRST_NAME_ATTRIBUTE);
idp.setFirstNameAttributeDescriptor(firstName);
SAMLAttributeDescriptor lastName = new SAMLAttributeDescriptor();
lastName.setNamespaceURI(SAMLConstants.LAST_NAME_ATTRIBUTE_NAMESPACE);
lastName.setName(SAMLConstants.LAST_NAME_ATTRIBUTE);
idp.setLastNameAttributeDescriptor(lastName);
SAMLAttributeDescriptor email = new SAMLAttributeDescriptor();
email.setNamespaceURI(SAMLConstants.EMAIL_ATTRIBUTE_NAMESPACE);
email.setName(SAMLConstants.EMAIL_ATTRIBUTE);
idp.setEmailAttributeDescriptor(email);
GridUser usr = null;
try {
LocalUser idpUsr = identityProvider.getUser(IDP_ADMIN_USER_ID, IDP_ADMIN_USER_ID);
usr = new GridUser();
usr.setUID(idpUsr.getUserId());
usr.setFirstName(idpUsr.getFirstName());
usr.setLastName(idpUsr.getLastName());
usr.setEmail(idpUsr.getEmail());
usr.setUserStatus(GridUserStatus.ACTIVE);
} catch (Exception e) {
}
ifsConfiguration = dorianProperties.getIdentityFederationProperties();
FederationDefaults defaults = new FederationDefaults(idp, usr);
boolean ignoreCRL = true;
List<String> crls = ifsConfiguration.getCRLPublishingList();
if (crls != null) {
for (String crl : crls) {
if (!StringUtils.isBlank(crl)) {
ignoreCRL = false;
}
}
}
ifm = new IdentityFederationManager(ifsConfiguration, db, propertyManager, caManager, this.eventManager, defaults, ignoreCRL);
if (!propertyManager.getVersion().equals(PropertyManager.CURRENT_VERSION)) {
DorianInternalException fault = FaultHelper.createFaultException(DorianInternalException.class, "Version conflict detected, your are running Dorian " + PropertyManager.CURRENT_VERSION
+ " against a Dorian " + propertyManager.getVersion() + " database.");
throw fault;
}
}
}