Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -20,4 +20,7 @@ rest/.miredot-offline.json
itests/src/main
dependency_tree.txt
.mvn/.develocity/develocity-workspace-id
/.cursor/
/.local-notes/
itests/snapshots_repository/
.env.local
10 changes: 10 additions & 0 deletions api/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,16 @@
<artifactId>jackson-databind</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.osgi</groupId>
<artifactId>osgi.core</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.yaml</groupId>
<artifactId>snakeyaml</artifactId>
Expand Down
21 changes: 21 additions & 0 deletions api/src/main/java/org/apache/unomi/api/ContextRequest.java
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,11 @@ public class ContextRequest {

private String clientId;

/**
* The public API key for tenant authentication.
*/
private String publicApiKey;

/**
* Retrieves the source of the context request.
*
Expand Down Expand Up @@ -294,4 +299,20 @@ public String getClientId() {
public void setClientId(String clientId) {
this.clientId = clientId;
}

/**
* Gets the public API key used for tenant authentication.
* @return the public API key
*/
public String getPublicApiKey() {
return publicApiKey;
}

/**
* Sets the public API key used for tenant authentication.
* @param publicApiKey the public API key to set
*/
public void setPublicApiKey(String publicApiKey) {
this.publicApiKey = publicApiKey;
}
}
2 changes: 0 additions & 2 deletions api/src/main/java/org/apache/unomi/api/ContextResponse.java
Original file line number Diff line number Diff line change
Expand Up @@ -20,10 +20,8 @@
import org.apache.unomi.api.conditions.Condition;
import org.apache.unomi.api.services.RulesService;

import javax.xml.bind.annotation.XmlTransient;
import java.io.Serializable;
import java.util.*;
import java.util.stream.Collectors;

/**
* A context server response resulting from the evaluation of a client's context request. Note that all returned values result of the evaluation of the data provided in the
Expand Down
7 changes: 6 additions & 1 deletion api/src/main/java/org/apache/unomi/api/Event.java
Original file line number Diff line number Diff line change
Expand Up @@ -152,7 +152,9 @@ private void initEvent(String eventType, Session session, Profile profile, Strin
this.eventType = eventType;
this.profile = profile;
this.session = session;
this.profileId = profile.getItemId();
if (profile != null) {
this.profileId = profile.getItemId();
}
this.scope = scope;
this.source = source;
this.target = target;
Expand Down Expand Up @@ -319,6 +321,9 @@ public void setAttributes(Map<String, Object> attributes) {
* @param value the value of the property
*/
public void setProperty(String name, Object value) {
if (properties == null) {
properties = new LinkedHashMap<>();
}
properties.put(name, value);
}

Expand Down
21 changes: 21 additions & 0 deletions api/src/main/java/org/apache/unomi/api/EventsCollectorRequest.java
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,11 @@ public class EventsCollectorRequest {

private String profileId;

/**
* The public API key for tenant authentication.
*/
private String publicApiKey;

/**
* Retrieves the events to be processed.
*
Expand Down Expand Up @@ -81,4 +86,20 @@ public String getProfileId() {
public void setProfileId(String profileId) {
this.profileId = profileId;
}

/**
* Gets the public API key used for tenant authentication.
* @return the public API key
*/
public String getPublicApiKey() {
return publicApiKey;
}

/**
* Sets the public API key used for tenant authentication.
* @param publicApiKey the public API key to set
*/
public void setPublicApiKey(String publicApiKey) {
this.publicApiKey = publicApiKey;
}
}
98 changes: 98 additions & 0 deletions api/src/main/java/org/apache/unomi/api/ExecutionContext.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF 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
*
* 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.apache.unomi.api;

import java.util.HashSet;
import java.util.Set;
import java.util.Stack;

/**
* Represents the execution context for operations in Unomi, including security and tenant information.
*/
public class ExecutionContext {
public static final String SYSTEM_TENANT = "system";

private String tenantId;
private Set<String> roles = new HashSet<>();
private Set<String> permissions = new HashSet<>();
private Stack<String> tenantStack = new Stack<>();
private boolean isSystem = false;

public ExecutionContext(String tenantId, Set<String> roles, Set<String> permissions) {
this.tenantId = tenantId;
if (tenantId != null && tenantId.equals(SYSTEM_TENANT)) {
this.isSystem = true;
}
if (roles != null) {
this.roles.addAll(roles);
}
if (permissions != null) {
this.permissions.addAll(permissions);
}
}

public static ExecutionContext systemContext() {
ExecutionContext context = new ExecutionContext(SYSTEM_TENANT, null, null);
context.isSystem = true;
return context;
}

public String getTenantId() {
return tenantId;
}

public Set<String> getRoles() {
return new HashSet<>(roles);
}

public Set<String> getPermissions() {
return new HashSet<>(permissions);
}

public boolean isSystem() {
return isSystem;
}

public void setTenant(String tenantId) {
tenantStack.push(this.tenantId);
this.tenantId = tenantId;
}

public void restorePreviousTenant() {
if (!tenantStack.isEmpty()) {
this.tenantId = tenantStack.pop();
}
}

public void validateAccess(String operation) {
if (isSystem) {
return;
}

if (!hasPermission(operation)) {
throw new SecurityException("Access denied: Missing permission for operation " + operation + " for tenant " + tenantId + " and roles " + roles);
}
}

public boolean hasPermission(String permission) {
return isSystem || permissions.contains(permission);
}

public boolean hasRole(String role) {
return isSystem || roles.contains(role);
}
}
80 changes: 79 additions & 1 deletion api/src/main/java/org/apache/unomi/api/Item.java
Original file line number Diff line number Diff line change
Expand Up @@ -72,19 +72,34 @@ public static String getItemType(Class clazz) {
protected String scope;
protected Long version;
protected Map<String, Object> systemMetadata = new HashMap<>();
private String tenantId;

// Audit metadata fields
private String createdBy;
private String lastModifiedBy;
private Date creationDate;
private Date lastModificationDate;
private String sourceInstanceId;
private Date lastSyncDate;

public Item() {
this.itemType = getItemType(this.getClass());
if (itemType == null) {
LOGGER.error("Item implementations must provide a public String constant named ITEM_TYPE to uniquely identify this Item for the persistence service.");
}
initializeAuditMetadata();
}

public Item(String itemId) {
this();
this.itemId = itemId;
}

private void initializeAuditMetadata() {
this.creationDate = new Date();
this.lastModificationDate = this.creationDate;
this.version = 0L;
}

/**
* Retrieves the Item's identifier used to uniquely identify this Item when persisted or when referred to. An Item's identifier must be unique among Items with the same type.
Expand Down Expand Up @@ -134,7 +149,6 @@ public boolean equals(Object o) {
Item item = (Item) o;

return !(itemId != null ? !itemId.equals(item.itemId) : item.itemId != null);

}

@Override
Expand All @@ -158,6 +172,63 @@ public void setSystemMetadata(String key, Object value) {
systemMetadata.put(key, value);
}

public String getTenantId() {
return tenantId;
}

public void setTenantId(String tenantId) {
this.tenantId = tenantId;
}

// Audit metadata getters and setters
public String getCreatedBy() {
return createdBy;
}

public void setCreatedBy(String createdBy) {
this.createdBy = createdBy;
}

public String getLastModifiedBy() {
return lastModifiedBy;
}

public void setLastModifiedBy(String lastModifiedBy) {
this.lastModifiedBy = lastModifiedBy;
}

public Date getCreationDate() {
return creationDate;
}

public void setCreationDate(Date creationDate) {
this.creationDate = creationDate;
}

public Date getLastModificationDate() {
return lastModificationDate;
}

public void setLastModificationDate(Date lastModificationDate) {
this.lastModificationDate = lastModificationDate;
}

public String getSourceInstanceId() {
return sourceInstanceId;
}

public void setSourceInstanceId(String sourceInstanceId) {
this.sourceInstanceId = sourceInstanceId;
}

public Date getLastSyncDate() {
return lastSyncDate;
}

public void setLastSyncDate(Date lastSyncDate) {
this.lastSyncDate = lastSyncDate;
}

/**
* Converts this item to a Map structure for YAML output.
* Implements YamlConvertible interface with circular reference detection.
Expand Down Expand Up @@ -193,6 +264,13 @@ public Map<String, Object> toYaml(Set<Object> visited, int maxDepth) {
.putIfNotNull("scope", scope)
.putIfNotNull("version", version)
.putIfNotNull("systemMetadata", systemMetadata != null && !systemMetadata.isEmpty() ? toYamlValue(systemMetadata, visitedSet, maxDepth - 1) : null)
.putIfNotNull("tenantId", tenantId)
.putIfNotNull("createdBy", createdBy)
.putIfNotNull("lastModifiedBy", lastModifiedBy)
.putIfNotNull("creationDate", creationDate)
.putIfNotNull("lastModificationDate", lastModificationDate)
.putIfNotNull("sourceInstanceId", sourceInstanceId)
.putIfNotNull("lastSyncDate", lastSyncDate)
.build();
} finally {
// Only remove if we added it (i.e., if it wasn't already visited)
Expand Down
1 change: 0 additions & 1 deletion api/src/main/java/org/apache/unomi/api/Parameter.java
Original file line number Diff line number Diff line change
Expand Up @@ -119,5 +119,4 @@ public Map<String, Object> toYaml(Set<Object> visited, int maxDepth) {
public String toString() {
return YamlUtils.format(toYaml());
}

}
1 change: 1 addition & 0 deletions api/src/main/java/org/apache/unomi/api/Profile.java
Original file line number Diff line number Diff line change
Expand Up @@ -297,6 +297,7 @@ public String toString() {
sb.append(", itemId='").append(itemId).append('\'');
sb.append(", itemType='").append(itemType).append('\'');
sb.append(", scope='").append(scope).append('\'');
sb.append(", tenantId'").append(getTenantId()).append('\'');
sb.append(", version=").append(version);
sb.append('}');
return sb.toString();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,11 +18,12 @@
package org.apache.unomi.api;

import javax.xml.bind.annotation.XmlTransient;
import java.io.Serializable;

/**
* A unomi plugin that defines a new property merge strategy.
*/
public class PropertyMergeStrategyType implements PluginType {
public class PropertyMergeStrategyType implements PluginType, Serializable {

private String id;
private String filter;
Expand Down
3 changes: 2 additions & 1 deletion api/src/main/java/org/apache/unomi/api/ValueType.java
Original file line number Diff line number Diff line change
Expand Up @@ -18,13 +18,14 @@
package org.apache.unomi.api;

import javax.xml.bind.annotation.XmlTransient;
import java.io.Serializable;
import java.util.LinkedHashSet;
import java.util.Set;

/**
* A value type to be used to constrain property values.
*/
public class ValueType implements PluginType {
public class ValueType implements PluginType, Serializable {

private String id;
private String nameKey;
Expand Down
Loading
Loading