Hi everyone,
I am currently implementing the role-based access control
model for openhab users. For this, I am modifying the openhab-core project and need to store and manage roles in a registry in the same way as for users and items.
For the user the UserRegistryImpl.class does this functionality and for the items the ItemRegistryImpl.class does this functionality. Therefore, I implemented the RoleRegistryImpl.class.
Here you can see my class RoleRegistryImpl.class put at the location /openhab-core/bundles/org.openhab.core/src/main/java/org/openhab/core/internal/roles/RoleRegistryImpl.java
:
package org.openhab.core.internal.roles;
import java.util.HashSet;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.openhab.core.auth.*;
import org.openhab.core.common.registry.AbstractRegistry;
import org.openhab.core.items.ItemRegistry;
import org.osgi.framework.BundleContext;
import org.osgi.service.component.annotations.*;
/**
* @author Nicolas Gennart
*/
@NonNullByDefault
@Component(service = RoleRegistry.class, immediate = true)
public class RoleRegistryImpl extends AbstractRegistry<Role, String, RoleProvider> implements RoleRegistry {
private final ItemRegistry itemRegistry;
/**
* Constructor.
*
*/
@Activate
public RoleRegistryImpl(BundleContext bundleContext, @Reference ItemRegistry itemRegistry) {
super(RoleProvider.class);
super.activate(bundleContext);
this.itemRegistry = itemRegistry;
}
@Override
@Deactivate
protected void deactivate() {
super.deactivate();
}
@Reference(cardinality = ReferenceCardinality.OPTIONAL, policy = ReferencePolicy.DYNAMIC)
protected void setManagedProvider(ManagedRoleProvider managedProvider) {
super.setManagedProvider(managedProvider);
super.addProvider(managedProvider);
}
protected void unsetManagedProvider(ManagedRoleProvider managedProvider) {
super.unsetManagedProvider(managedProvider);
super.removeProvider(managedProvider);
}
@Override
public void updateRole(String oldRole, String newRole) {
ManagedRole managedrole = new ManagedRole(newRole);
// We check if the oldRole exist.
if (get(oldRole) != null) {
if (newRole.equals("administrator")) {
managedrole.setItemNames(itemRegistry.getAllItemNames());
}
remove(oldRole);
add(managedrole);
} else {
throw new IllegalArgumentException(
"The role " + oldRole + " does not exist in the roleRegistry so we can't change it.");
}
}
@Override
public void addRole(String role) {
ManagedRole managedrole = new ManagedRole(role);
// We check if the role does not exist.
if (get(role) == null) {
if (role.equals("administrator")) {
managedrole.setItemNames(itemRegistry.getAllItemNames());
}
add(managedrole);
} else {
throw new IllegalArgumentException(
"The role " + role + " already exist in the roleRegistry so we can not add it.");
}
}
@Override
public void removeRole(String role) {
// We check if the role exist.
if (get(role) != null) {
remove(role);
} else {
throw new IllegalArgumentException(
"The role " + role + " does not exist in the roleRegistry so we can not remove it.");
}
}
@Override
public void addItemsToRole(String role, HashSet<String> itemNames) {
ManagedRole managedRole = (ManagedRole) get(role);
// We check if the role in the registry exist.
if (managedRole != null) {
HashSet<String> roleItemNames = (HashSet<String>) managedRole.getItemNames();
// We check if the set changed
if (roleItemNames.addAll(itemNames)) {
managedRole.setItemNames(roleItemNames);
update(managedRole);
}
} else {
throw new IllegalArgumentException(
"The role " + role + " does not exist in the roleRegistry so we can not add items to it.");
}
}
@Override
public void removeItemsToRole(String role, HashSet<String> itemNames) {
ManagedRole managedRole = (ManagedRole) get(role);
// We check if the role in the registry exist.
if (managedRole != null) {
HashSet<String> roleItemNames = (HashSet<String>) managedRole.getItemNames();
// We check if the set changed
if (roleItemNames.removeAll(itemNames)) {
managedRole.setItemNames(roleItemNames);
update(managedRole);
}
} else {
throw new IllegalArgumentException(
"The role " + role + " does not exist in the roleRegistry so we can not remove items to it.");
}
}
}
I implemented the ManageRole.class which implements the Role interface at the location openhab-core/bundles/org.openhab.core/src/main/java/org/openhab/core/auth/ManagedRole.java
as shown below:
package org.openhab.core.auth;
import java.util.HashSet;
import java.util.Set;
/**
* @author Nicolas Gennart
*/
public class ManagedRole implements Role {
private final String role;
private Set<String> itemNames = new HashSet<>();
public ManagedRole(String role) {
this.role = role;
}
@Override
public String getRole() {
return role;
}
@Override
public String getUID() {
return role;
}
public Set<String> getItemNames() {
return itemNames;
}
public void setItemNames(Set<String> itemNames) {
this.itemNames = itemNames;
}
}
The interface RoleProvider like that:
package org.openhab.core.auth;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.openhab.core.common.registry.Provider;
/**
* @author Nicolas Gennart
*/
@NonNullByDefault
public interface RoleProvider extends Provider<Role> {
}
And the last class I need to implement is the ManagedRoleProvider.class at the location openhab-core/bundles/org.openhab.core/src/main/java/org/openhab/core/internal/roles/ManagedRoleProvider.java
to provide the Role objects and store them in a file as below :
package org.openhab.core.internal.roles;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.openhab.core.auth.ManagedUser;
import org.openhab.core.auth.Role;
import org.openhab.core.common.registry.DefaultAbstractManagedProvider;
import org.openhab.core.common.registry.ManagedProvider;
import org.openhab.core.storage.StorageService;
import org.osgi.service.component.annotations.Activate;
import org.osgi.service.component.annotations.Component;
import org.osgi.service.component.annotations.Reference;
/**
* A {@link ManagedProvider} for {@link ManagedUser} entities
*
* @author Yannick Schaus - initial contribution
*/
@NonNullByDefault
@Component(service = ManagedRoleProvider.class, immediate = true)
public class ManagedRoleProvider extends DefaultAbstractManagedProvider<Role, String> {
@Activate
public ManagedRoleProvider(final @Reference StorageService storageService) {
super(storageService);
}
@Override
protected String getStorageName() {
return "roles";
}
@Override
protected String keyToString(String key) {
return key;
}
}
So, the RoleRegistry works fine when I call it in another bundle but when I call the RoleRegistry.class in the same bundle (in the org.openhab.core bundle), it does not work and the org.openhab.core bundle remains in the Waiting state.
This is strange because I implemented the RoleRegistry exactly the same way as the UserRegistry and the UserRegistry can be called in another class in the same bundle. I also canât test the RoleRegistryImpl.class in the folder test
of the org.openhab.core bundle because I canât call the RoleRegistry.class in the same bundle.
Does anyone know what I need to do for the RoleRegistry and how it is done for the UserRegistry or for the ItemRegistry so that the RoleRegistry service can be used in its own bundle?
Thank you very much,
Nicolas Gennart.
PS: The code guidelines are not yet fully respected (like the import *) but I will do it later.