/**
* Copyright (c) 2011-2014, OpenIoT
*
* This library is free software; you can redistribute it and/or
* modify it either under the terms of the GNU Lesser General Public
* License version 2.1 as published by the Free Software Foundation
* (the "LGPL"). If you do not alter this
* notice, a recipient may use your version of this file under the LGPL.
*
* You should have received a copy of the LGPL along with this library
* in the file COPYING-LGPL-2.1; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
* OF ANY KIND, either express or implied. See the LGPL for
* the specific language governing rights and limitations.
*
* Contact: OpenIoT mailto: info@openiot.eu
*/
/*
* Licensed to Jasig under one or more contributor license
* agreements. See the NOTICE file distributed with this work
* for additional information regarding copyright ownership.
* Jasig licenses this file to you under the Apache License,
* Version 2.0 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a
* copy of the License at the following location:
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.openiot.security.oauth;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.TreeSet;
import java.util.concurrent.ConcurrentHashMap;
import javax.validation.constraints.NotNull;
import org.jasig.cas.authentication.principal.Service;
import org.jasig.cas.services.RegisteredService;
import org.jasig.cas.services.RegisteredServiceImpl;
import org.jasig.cas.services.ReloadableServicesManager;
import org.jasig.cas.services.ServiceRegistryDao;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.transaction.annotation.Transactional;
import com.github.inspektr.audit.annotation.Audit;
public class OpenIoTServicesManagerImpl implements ReloadableServicesManager {
private final Logger log = LoggerFactory.getLogger(getClass());
/** Instance of ServiceRegistryDao. */
@NotNull
private ServiceRegistryDao serviceRegistryDao;
/** Map to store all services. */
private ConcurrentHashMap<Long, RegisteredService> services = new ConcurrentHashMap<Long, RegisteredService>();
/** Default service to return if none have been registered. */
private RegisteredService disabledRegisteredService;
public OpenIoTServicesManagerImpl(final ServiceRegistryDao serviceRegistryDao) {
this(serviceRegistryDao, new ArrayList<String>());
}
/**
* Constructs an instance of the {@link DefaultServicesManagerImpl} where the default
* RegisteredService can include a set of default attributes to use if no services are defined
* in the registry.
*
* @param serviceRegistryDao
* the Service Registry Dao.
* @param defaultAttributes
* the list of default attributes to use.
*/
public OpenIoTServicesManagerImpl(final ServiceRegistryDao serviceRegistryDao, final List<String> defaultAttributes) {
this.serviceRegistryDao = serviceRegistryDao;
this.disabledRegisteredService = constructDefaultRegisteredService(defaultAttributes);
load();
}
@Transactional(readOnly = false)
@Audit(action = "DELETE_SERVICE", actionResolverName = "DELETE_SERVICE_ACTION_RESOLVER", resourceResolverName = "DELETE_SERVICE_RESOURCE_RESOLVER")
public synchronized RegisteredService delete(final long id) {
final RegisteredService r = findServiceBy(id);
if (r == null) {
return null;
}
this.serviceRegistryDao.delete(r);
this.services.remove(id);
return r;
}
/**
* Note, if the repository is empty, this implementation will return a default service to grant
* all access.
* <p>
* This preserves default CAS behavior.
*/
public RegisteredService findServiceBy(final Service service) {
final Collection<RegisteredService> c = convertToTreeSet();
if (c.isEmpty()) {
return this.disabledRegisteredService;
}
for (final RegisteredService r : c) {
if (r.matches(service)) {
return r;
}
}
return null;
}
public RegisteredService findServiceBy(final long id) {
final RegisteredService r = this.services.get(id);
try {
return r == null ? null : (RegisteredService) r.clone();
} catch (final CloneNotSupportedException e) {
return r;
}
}
protected TreeSet<RegisteredService> convertToTreeSet() {
return new TreeSet<RegisteredService>(this.services.values());
}
public Collection<RegisteredService> getAllServices() {
return Collections.unmodifiableCollection(convertToTreeSet());
}
public boolean matchesExistingService(final Service service) {
return findServiceBy(service) != null;
}
@Transactional(readOnly = false)
@Audit(action = "SAVE_SERVICE", actionResolverName = "SAVE_SERVICE_ACTION_RESOLVER", resourceResolverName = "SAVE_SERVICE_RESOURCE_RESOLVER")
public synchronized RegisteredService save(final RegisteredService registeredService) {
final RegisteredService r = this.serviceRegistryDao.save(registeredService);
this.services.put(r.getId(), r);
return r;
}
public void reload() {
log.info("Reloading registered services.");
load();
}
private void load() {
final ConcurrentHashMap<Long, RegisteredService> localServices = new ConcurrentHashMap<Long, RegisteredService>();
for (final RegisteredService r : this.serviceRegistryDao.load()) {
log.debug("Adding registered service " + r.getServiceId());
localServices.put(r.getId(), r);
}
this.services = localServices;
log.info(String.format("Loaded %s services.", this.services.size()));
}
private RegisteredService constructDefaultRegisteredService(final List<String> attributes) {
final RegisteredServiceImpl r = new RegisteredServiceImpl();
r.setAllowedToProxy(true);
r.setAnonymousAccess(false);
r.setEnabled(true);
r.setSsoEnabled(true);
r.setAllowedAttributes(attributes);
if (attributes == null || attributes.isEmpty()) {
r.setIgnoreAttributes(true);
}
return r;
}
}