/******************************************************************************* * Cloud Foundry * Copyright (c) [2009-2016] Pivotal Software, Inc. All Rights Reserved. * * This product is licensed to you under the Apache License, Version 2.0 (the "License"). * You may not use this product except in compliance with the License. * * This product includes a number of subcomponents with * separate copyright notices and license terms. Your use of these * subcomponents is subject to the terms and conditions of the * subcomponent's license, as noted in the LICENSE file. *******************************************************************************/ package org.cloudfoundry.identity.uaa.provider.saml.idp; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.cloudfoundry.identity.uaa.provider.JdbcIdentityProviderProvisioning; import org.cloudfoundry.identity.uaa.util.JsonUtils; import org.cloudfoundry.identity.uaa.zone.IdentityZoneHolder; import org.springframework.dao.DataIntegrityViolationException; import org.springframework.dao.DuplicateKeyException; import org.springframework.jdbc.core.JdbcTemplate; import org.springframework.jdbc.core.PreparedStatementSetter; import org.springframework.jdbc.core.RowMapper; import org.springframework.util.Assert; import org.springframework.util.StringUtils; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; import java.sql.Timestamp; import java.util.Date; import java.util.List; import java.util.UUID; /** * Rest-template-based data access for SAML Service Provider CRUD operations. */ public class JdbcSamlServiceProviderProvisioning implements SamlServiceProviderProvisioning, SamlServiceProviderDeletable { private static final Log LOGGER = LogFactory.getLog(JdbcIdentityProviderProvisioning.class); public static final String SERVICE_PROVIDER_FIELDS = "id,version,created,lastmodified,name,entity_id,config,identity_zone_id,active"; public static final String CREATE_SERVICE_PROVIDER_SQL = "insert into service_provider(" + SERVICE_PROVIDER_FIELDS + ") values (?,?,?,?,?,?,?,?,?)"; public static final String DELETE_SERVICE_PROVIDER_SQL = "delete from service_provider where id=? and identity_zone_id=?"; public static final String DELETE_SERVICE_PROVIDER_BY_ENTITY_ID_SQL = "delete from service_provider where entity_id = ? and identity_zone_id=?"; public static final String DELETE_SERVICE_PROVIDER_BY_ZONE_SQL = "delete from service_provider where identity_zone_id=?"; public static final String SERVICE_PROVIDERS_QUERY = "select " + SERVICE_PROVIDER_FIELDS + " from service_provider where identity_zone_id=?"; public static final String ACTIVE_SERVICE_PROVIDERS_QUERY = SERVICE_PROVIDERS_QUERY + " and active=?"; public static final String SERVICE_PROVIDER_UPDATE_FIELDS = "version,lastmodified,name,config,active".replace(",", "=?,") + "=?"; public static final String UPDATE_SERVICE_PROVIDER_SQL = "update service_provider set " + SERVICE_PROVIDER_UPDATE_FIELDS + " where id=? and identity_zone_id=?"; public static final String SERVICE_PROVIDER_BY_ID_QUERY = "select " + SERVICE_PROVIDER_FIELDS + " from service_provider " + "where id=? and identity_zone_id=?"; public static final String SERVICE_PROVIDER_BY_ENTITY_ID_QUERY = "select " + SERVICE_PROVIDER_FIELDS + " from service_provider " + "where entity_id=? and identity_zone_id=? "; protected final JdbcTemplate jdbcTemplate; private final RowMapper<SamlServiceProvider> mapper = new SamlServiceProviderRowMapper(); public JdbcSamlServiceProviderProvisioning(JdbcTemplate jdbcTemplate) { Assert.notNull(jdbcTemplate); this.jdbcTemplate = jdbcTemplate; } @Override public SamlServiceProvider retrieve(String id) { SamlServiceProvider serviceProvider = jdbcTemplate.queryForObject(SERVICE_PROVIDER_BY_ID_QUERY, mapper, id, IdentityZoneHolder.get().getId()); return serviceProvider; } @Override public void delete(String id) { jdbcTemplate.update(DELETE_SERVICE_PROVIDER_SQL, id, IdentityZoneHolder.get().getId()); } @Override public int deleteByEntityId(String entityId, String zoneId) { return jdbcTemplate.update(DELETE_SERVICE_PROVIDER_BY_ENTITY_ID_SQL, entityId, zoneId); } @Override public int deleteByIdentityZone(String zoneId) { return jdbcTemplate.update(DELETE_SERVICE_PROVIDER_BY_ZONE_SQL, zoneId); } @Override public List<SamlServiceProvider> retrieveActive(String zoneId) { return jdbcTemplate.query(ACTIVE_SERVICE_PROVIDERS_QUERY, mapper, zoneId, true); } @Override public List<SamlServiceProvider> retrieveAll(boolean activeOnly, String zoneId) { if (activeOnly) { return retrieveActive(zoneId); } else { return jdbcTemplate.query(SERVICE_PROVIDERS_QUERY, mapper, zoneId); } } @Override public SamlServiceProvider retrieveByEntityId(String entityId, String zoneId) { SamlServiceProvider serviceProvider = jdbcTemplate.queryForObject(SERVICE_PROVIDER_BY_ENTITY_ID_QUERY, mapper, entityId, zoneId); return serviceProvider; } @Override public SamlServiceProvider create(final SamlServiceProvider serviceProvider) { validate(serviceProvider); final String id = UUID.randomUUID().toString(); try { jdbcTemplate.update(CREATE_SERVICE_PROVIDER_SQL, new PreparedStatementSetter() { @Override public void setValues(PreparedStatement ps) throws SQLException { int pos = 1; ps.setString(pos++, id); ps.setInt(pos++, serviceProvider.getVersion()); ps.setTimestamp(pos++, new Timestamp(System.currentTimeMillis())); ps.setTimestamp(pos++, new Timestamp(System.currentTimeMillis())); ps.setString(pos++, serviceProvider.getName()); ps.setString(pos++, serviceProvider.getEntityId()); ps.setString(pos++, JsonUtils.writeValueAsString(serviceProvider.getConfig())); ps.setString(pos++, serviceProvider.getIdentityZoneId()); ps.setBoolean(pos++, serviceProvider.isActive()); } }); } catch (DuplicateKeyException e) { throw new SamlSpAlreadyExistsException(e.getMostSpecificCause().getMessage()); } return retrieve(id); } @Override public SamlServiceProvider update(final SamlServiceProvider serviceProvider) { validate(serviceProvider); final String zoneId = IdentityZoneHolder.get().getId(); jdbcTemplate.update(UPDATE_SERVICE_PROVIDER_SQL, new PreparedStatementSetter() { @Override public void setValues(PreparedStatement ps) throws SQLException { int pos = 1; ps.setInt(pos++, serviceProvider.getVersion() + 1); ps.setTimestamp(pos++, new Timestamp(new Date().getTime())); ps.setString(pos++, serviceProvider.getName()); ps.setString(pos++, JsonUtils.writeValueAsString(serviceProvider.getConfig())); ps.setBoolean(pos++, serviceProvider.isActive()); ps.setString(pos++, serviceProvider.getId().trim()); ps.setString(pos++, zoneId); } }); return retrieve(serviceProvider.getId()); } protected void validate(SamlServiceProvider provider) { if (provider == null) { throw new NullPointerException("SAML Service Provider can not be null."); } if (!StringUtils.hasText(provider.getIdentityZoneId())) { throw new DataIntegrityViolationException("Identity zone ID must be set."); } } private static final class SamlServiceProviderRowMapper implements RowMapper<SamlServiceProvider> { public SamlServiceProviderRowMapper() { // Default constructor. } @Override public SamlServiceProvider mapRow(ResultSet rs, int rowNum) throws SQLException { SamlServiceProvider samlServiceProvider = new SamlServiceProvider(); int pos = 1; samlServiceProvider.setId(rs.getString(pos++).trim()); samlServiceProvider.setVersion(rs.getInt(pos++)); samlServiceProvider.setCreated(rs.getTimestamp(pos++)); samlServiceProvider.setLastModified(rs.getTimestamp(pos++)); samlServiceProvider.setName(rs.getString(pos++)); samlServiceProvider.setEntityId(rs.getString(pos++)); String config = rs.getString(pos++); SamlServiceProviderDefinition definition = JsonUtils.readValue(config, SamlServiceProviderDefinition.class); samlServiceProvider.setConfig(definition); samlServiceProvider.setIdentityZoneId(rs.getString(pos++)); samlServiceProvider.setActive(rs.getBoolean(pos++)); return samlServiceProvider; } } @Override public Log getLogger() { return LOGGER; } }