Merge remote-tracking branch 'server/master'

This commit is contained in:
Axel Uhl committed 2020-03-09 12:47:21 +01:00
commit b295e80344
12 files changed
+147 -89

No files matched your search

@@ -263,7 +263,6 @@ public enum DetailType implements Serializable {
availableDetailsTypes.add(DetailType.LEG_GAP_TO_LEADER_IN_SECONDS);
availableDetailsTypes.add(DetailType.RACE_CURRENT_SPEED_OVER_GROUND_IN_KNOTS);
availableDetailsTypes.add(DetailType.RACE_RANK);
availableDetailsTypes.add(DetailType.RACE_IMPLIED_WIND);
availableDetailsTypes.add(DetailType.REGATTA_RANK);
availableDetailsTypes.add(DetailType.CHART_DISTANCE_TO_START_LINE);
availableDetailsTypes.add(DetailType.CHART_BEAT_ANGLE);
@@ -390,9 +389,8 @@ public enum DetailType implements Serializable {
}
/**
* Returns all types in the enum, minus those for expedition, bravo and bravo extended
*
* @return
* Returns all types in the enum, minus those for expedition, bravo, bravo extended
* and the ToT/ToD/ORC PCS ones
*/
public static Collection<DetailType> getAllNonRestrictedDetailTypes() {
final Collection<DetailType> all = new LinkedHashSet<>(Arrays.asList(values()));
@@ -402,6 +400,8 @@ public enum DetailType implements Serializable {
all.removeAll(getRaceExpeditionDetailTypes());
all.removeAll(getLegExpeditionDetailColumnTypes());
all.removeAll(getOverallBravoDetailTypes());
all.removeAll(getAllToTToDHandicapDetailTypes());
all.removeAll(getAllOrcPerformanceCurveDetailTypes());
return all;
}
@@ -73,4 +73,10 @@ public interface CompetitorDTO extends Named, WithID, SecuredDTO, Serializable,
* from the previous version of the enclosing leaderboard.
*/
CompetitorDTO getCompetitorFromPrevious(LeaderboardDTO previousVersion);
/**
* Erases the fields a user is not supposed to read with only the READ_PUBLIC and not the
* READ permission.
*/
void clearNonPublicFields();
}
@@ -260,4 +260,9 @@ public class CompetitorDTOImpl extends NamedSecuredObjectDTO implements Competit
return new TypeRelativeObjectIdentifier(idAsString);
}
@Override
public void clearNonPublicFields() {
email = null;
}
}
@@ -150,6 +150,12 @@ public class PreviousCompetitorDTOImpl extends NamedSecuredObjectDTO implements
" need to be replaced by an object of "+CompetitorWithBoatDTOImpl.class.getName()+" after deserialization");
}
@Override
public void clearNonPublicFields() {
throw new RuntimeException("Internal error. Objects of type "+PreviousCompetitorDTOImpl.class.getName()+
" need to be replaced by an object of "+CompetitorWithBoatDTOImpl.class.getName()+" after deserialization");
}
@Override
public Double getTimeOnTimeFactor() {
throw new RuntimeException("Internal error. Objects of type "+PreviousCompetitorDTOImpl.class.getName()+
@@ -72,20 +72,15 @@ public class EventSeriesLeaderboardsTabView extends Composite implements SeriesT
public void start(final EventSeriesLeaderboardsPlace myPlace, final AcceptsOneWidget contentArea) {
contentArea.setWidget(currentPresenter.getErrorAndBusyClientFactory().createBusyView());
String leaderboardName = currentPresenter.getSeriesDTO().getLeaderboardId();
if (leaderboardName != null && !leaderboardName.isEmpty()) {
final EventSeriesAnalyticsDataManager regattaAnalyticsManager = currentPresenter.getCtx()
.getAnalyticsManager();
regattaAnalyticsManager.getAvailableDetailTypesForLeaderboard(leaderboardName,
null, new AsyncCallback<Iterable<DetailType>>() {
@Override
public void onSuccess(Iterable<DetailType> result) {
final boolean autoExpandLastRaceColumn = GwtHttpRequestUtils.getBooleanParameter(
LeaderboardUrlSettings.PARAM_AUTO_EXPAND_LAST_RACE_COLUMN, false);
final ComponentContext<MultiRaceLeaderboardSettings> componentContext = createLeaderboardComponentContext(
leaderboardName, currentPresenter.getUserService(), /* FIXME placeToken */ null, result);
componentContext.getInitialSettings(
@@ -93,32 +88,19 @@ public class EventSeriesLeaderboardsTabView extends Composite implements SeriesT
@Override
public void onSuccess(MultiRaceLeaderboardSettings settings) {
MultiLeaderboardProxyPanel leaderboardPanel = regattaAnalyticsManager
.createMultiLeaderboardPanel(null, componentContext, settings, null, // TODO:
// preselectedLeaderboardName
"leaderboardGroupName", leaderboardName, true, // TODO @FM
// this
// information
// came from
// place, now
// hard
// coded.
// check with
// frank
.createMultiLeaderboardPanel(null, componentContext, settings, null, // TODO: preselectedLeaderboardName
"leaderboardGroupName", leaderboardName, true, // TODO @FM this information came from place, now hard coded. check with frank
autoExpandLastRaceColumn, result);
leaderboardPanel.addAttachHandler(new Handler() {
@Override
public void onAttachOrDetach(AttachEvent event) {
if (!event.isAttached()) {
componentContext.dispose();
}
}
});
initWidget(
ourUiBinder.createAndBindUi(EventSeriesLeaderboardsTabView.this));
leaderboard.setMultiLeaderboard(leaderboardPanel,
currentPresenter.getAutoRefreshTimer());
leaderboardPanel
@@ -133,7 +115,6 @@ public class EventSeriesLeaderboardsTabView extends Composite implements SeriesT
regattaAnalyticsManager.hideCompetitorChart();
leaderboardPanel.setVisible(true);
contentArea.setWidget(EventSeriesLeaderboardsTabView.this);
}
});
}
@@ -1363,12 +1363,22 @@ public class SailingServiceImpl extends ResultCachingProxiedRemoteServiceServlet
private CompetitorDTO convertToCompetitorDTO(Competitor competitor) {
CompetitorDTO competitorDTO = baseDomainFactory.convertToCompetitorDTO(competitor);
SecurityDTOUtil.addSecurityInformation(getSecurityService(), competitorDTO, competitor.getIdentifier());
clearNonPublicFieldsIfCurrentUserHasNoReadPermission(competitor, competitorDTO);
return competitorDTO;
}
private void clearNonPublicFieldsIfCurrentUserHasNoReadPermission(Competitor competitor,
CompetitorDTO competitorDTO) {
if (!getSecurityService().hasCurrentUserReadPermission(competitor)) {
// probably only READ_PUBLIC; remove e-mail address from DTO:
competitorDTO.clearNonPublicFields();
}
}
private CompetitorWithBoatDTO convertToCompetitorWithBoatDTO(CompetitorWithBoat competitor) {
CompetitorWithBoatDTO competitorDTO = baseDomainFactory.convertToCompetitorWithBoatDTO(competitor);
SecurityDTOUtil.addSecurityInformation(getSecurityService(), competitorDTO, competitor.getIdentifier());
clearNonPublicFieldsIfCurrentUserHasNoReadPermission(competitor, competitorDTO);
BoatDTO boatDTO = competitorDTO.getBoat();
SecurityDTOUtil.addSecurityInformation(getSecurityService(), boatDTO, competitor.getBoat().getIdentifier());
return competitorDTO;
@@ -1383,6 +1393,7 @@ public class SailingServiceImpl extends ResultCachingProxiedRemoteServiceServlet
for (final Entry<? extends Competitor, ? extends Boat> c : competitorsAndTheirBoats.entrySet()) {
CompetitorAndBoatDTO competitorAndBoatDTO = baseDomainFactory.convertToCompetitorAndBoatDTO(c.getKey(), c.getValue());
SecurityDTOUtil.addSecurityInformation(getSecurityService(), competitorAndBoatDTO.getCompetitor(), c.getKey().getIdentifier());
clearNonPublicFieldsIfCurrentUserHasNoReadPermission(c.getKey(), competitorAndBoatDTO.getCompetitor());
SecurityDTOUtil.addSecurityInformation(getSecurityService(), competitorAndBoatDTO.getBoat(), c.getValue().getIdentifier());
result.add(competitorAndBoatDTO);
}
@@ -1398,6 +1409,7 @@ public class SailingServiceImpl extends ResultCachingProxiedRemoteServiceServlet
for (CompetitorWithBoat c : iterable) {
CompetitorWithBoatDTO competitorDTO = baseDomainFactory.convertToCompetitorWithBoatDTO(c);
SecurityDTOUtil.addSecurityInformation(getSecurityService(), competitorDTO, c.getIdentifier());
clearNonPublicFieldsIfCurrentUserHasNoReadPermission(c, competitorDTO);
SecurityDTOUtil.addSecurityInformation(getSecurityService(), competitorDTO.getBoat(), c.getBoat().getIdentifier());
result.add(competitorDTO);
}
@@ -8328,9 +8340,9 @@ public class SailingServiceImpl extends ResultCachingProxiedRemoteServiceServlet
@Override
public Iterable<DetailType> determineDetailTypesForCompetitorChart(String leaderboardGroupName, RegattaAndRaceIdentifier identifier) {
final LinkedHashSet<DetailType> availableDetailsTypes = new LinkedHashSet<>();
availableDetailsTypes.addAll(DetailType.getAutoplayDetailTypesForChart());
availableDetailsTypes.removeAll(DetailType.getRaceBravoDetailTypes());
final LinkedHashSet<DetailType> availableDetailTypes = new LinkedHashSet<>();
availableDetailTypes.addAll(DetailType.getAutoplayDetailTypesForChart());
availableDetailTypes.removeAll(DetailType.getRaceBravoDetailTypes());
final DynamicTrackedRace trackedRace = getService().getTrackedRace(identifier);
if (trackedRace != null) {
boolean hasBravoTrack = false;
@@ -8343,31 +8355,36 @@ public class SailingServiceImpl extends ResultCachingProxiedRemoteServiceServlet
}
}
if (hasBravoTrack) {
availableDetailsTypes.addAll(DetailType.getRaceBravoDetailTypes());
availableDetailTypes.addAll(DetailType.getRaceBravoDetailTypes());
}
if (hasExtendedBravoFixes) {
availableDetailsTypes.addAll(DetailType.getRaceExtendedBravoDetailTypes());
availableDetailsTypes.addAll(DetailType.getRaceExpeditionDetailTypes());
availableDetailTypes.addAll(DetailType.getRaceExtendedBravoDetailTypes());
availableDetailTypes.addAll(DetailType.getRaceExpeditionDetailTypes());
}
final RankingMetrics rankingMetricType = trackedRace.getRankingMetric().getType();
switch (rankingMetricType) {
case ONE_DESIGN:
availableDetailTypes.removeAll(DetailType.getAllToTToDHandicapDetailTypes());
availableDetailTypes.removeAll(DetailType.getAllOrcPerformanceCurveDetailTypes());
break;
case TIME_ON_TIME_AND_DISTANCE:
availableDetailTypes.addAll(DetailType.getAllToTToDHandicapDetailTypes());
availableDetailTypes.removeAll(DetailType.getAllOrcPerformanceCurveDetailTypes());
break;
case ORC_PERFORMANCE_CURVE:
case ORC_PERFORMANCE_CURVE_BY_IMPLIED_WIND:
case ORC_PERFORMANCE_CURVE_LEADER_FOR_BASELINE:
availableDetailsTypes.addAll(DetailType.getAllOrcPerformanceCurveDetailTypes());
availableDetailTypes.addAll(DetailType.getAllOrcPerformanceCurveDetailTypes());
break;
}
}
if (leaderboardGroupName != null) {
final LeaderboardGroupDTO group = getLeaderboardGroupByName(leaderboardGroupName, false);
if (group != null ? group.hasOverallLeaderboard() : false) {
availableDetailsTypes.add(DetailType.OVERALL_RANK);
availableDetailTypes.add(DetailType.OVERALL_RANK);
}
}
return availableDetailsTypes;
return availableDetailTypes;
}
@Override
@@ -170,42 +170,46 @@ public class Activator implements BundleActivator {
new Thread("ServiceTracker waiting for Replicables "+Arrays.toString(replicableIdsAsStrings)) {
@Override
public void run() {
logger.info("Waiting for Replicables " + Arrays.toString(replicableIdsAsStrings) +
" before firing up replication automatically...");
final List<Replicable<?, ?>> replicables = new ArrayList<>();
for (String replicableIdAsString : replicableIdsAsStrings) {
Replicable<?, ?> replicable = replicablesProvider.getReplicable(replicableIdAsString, /* wait */true);
logger.info("Obtained Replicable " + replicableIdAsString);
replicables.add(replicable);
}
logger.info("Configuration requested automatic replication for replicables "+
Arrays.toString(replicableIdsAsStrings)+". Starting it up...");
String replicateFromExchangeName = System.getProperty(PROPERTY_NAME_REPLICATE_MASTER_EXCHANGE_NAME);
if (replicateFromExchangeName == null) {
replicateFromExchangeName = masterExchangeName;
}
final String servletHost = System.getProperty(PROPERTY_NAME_REPLICATE_MASTER_SERVLET_HOST);
final int servletPort = Integer.valueOf(System.getProperty(PROPERTY_NAME_REPLICATE_MASTER_SERVLET_PORT).trim());
final String bearerToken;
if (System.getProperty(PROPERTY_NAME_REPLICATE_MASTER_BEARER_TOKEN) != null) {
bearerToken = System.getProperty(PROPERTY_NAME_REPLICATE_MASTER_BEARER_TOKEN).trim();
} else {
bearerToken = RemoteServerUtil.resolveBearerTokenForRemoteServer(servletHost, servletPort,
System.getProperty(PROPERTY_NAME_REPLICATE_MASTER_USERNAME),
System.getProperty(PROPERTY_NAME_REPLICATE_MASTER_PASSWORD));
}
ReplicationMasterDescriptorImpl master = new ReplicationMasterDescriptorImpl(
System.getProperty(PROPERTY_NAME_REPLICATE_MASTER_QUEUE_HOST),
replicateFromExchangeName,
Integer.valueOf(System.getProperty(PROPERTY_NAME_REPLICATE_MASTER_QUEUE_PORT).trim()),
serverReplicationMasterService.getServerIdentifier().toString(),
servletHost, servletPort, bearerToken, replicables);
try {
serverReplicationMasterService.startToReplicateFrom(master);
serverReplicationMasterService.setReplicationStarting(false);
logger.info("Automatic replication has been started.");
} catch (ClassNotFoundException | IOException | InterruptedException e) {
logger.log(Level.SEVERE, "Error with automatic replication from "+master, e);
logger.info("Waiting for Replicables " + Arrays.toString(replicableIdsAsStrings) +
" before firing up replication automatically...");
final List<Replicable<?, ?>> replicables = new ArrayList<>();
for (String replicableIdAsString : replicableIdsAsStrings) {
Replicable<?, ?> replicable = replicablesProvider.getReplicable(replicableIdAsString, /* wait */true);
logger.info("Obtained Replicable " + replicableIdAsString);
replicables.add(replicable);
}
logger.info("Configuration requested automatic replication for replicables "+
Arrays.toString(replicableIdsAsStrings)+". Starting it up...");
String replicateFromExchangeName = System.getProperty(PROPERTY_NAME_REPLICATE_MASTER_EXCHANGE_NAME);
if (replicateFromExchangeName == null) {
replicateFromExchangeName = masterExchangeName;
}
final String servletHost = System.getProperty(PROPERTY_NAME_REPLICATE_MASTER_SERVLET_HOST);
final int servletPort = Integer.valueOf(System.getProperty(PROPERTY_NAME_REPLICATE_MASTER_SERVLET_PORT).trim());
final String bearerToken;
if (System.getProperty(PROPERTY_NAME_REPLICATE_MASTER_BEARER_TOKEN) != null) {
bearerToken = System.getProperty(PROPERTY_NAME_REPLICATE_MASTER_BEARER_TOKEN).trim();
} else {
bearerToken = RemoteServerUtil.resolveBearerTokenForRemoteServer(servletHost, servletPort,
System.getProperty(PROPERTY_NAME_REPLICATE_MASTER_USERNAME),
System.getProperty(PROPERTY_NAME_REPLICATE_MASTER_PASSWORD));
}
ReplicationMasterDescriptorImpl master = new ReplicationMasterDescriptorImpl(
System.getProperty(PROPERTY_NAME_REPLICATE_MASTER_QUEUE_HOST),
replicateFromExchangeName,
Integer.valueOf(System.getProperty(PROPERTY_NAME_REPLICATE_MASTER_QUEUE_PORT).trim()),
serverReplicationMasterService.getServerIdentifier().toString(),
servletHost, servletPort, bearerToken, replicables);
try {
serverReplicationMasterService.startToReplicateFrom(master);
serverReplicationMasterService.setReplicationStarting(false);
logger.info("Automatic replication has been started.");
} catch (ClassNotFoundException | IOException | InterruptedException e) {
logger.log(Level.SEVERE, "Error with automatic replication from "+master, e);
}
} catch (Exception e) {
logger.log(Level.SEVERE, "Error starting automatic replication", e);
}
}
}.start();
@@ -155,4 +155,11 @@ public class UserDTO extends
return new TypeRelativeObjectIdentifier(getName());
}
/**
* Erases the fields a user is not supposed to read with only the READ_PUBLIC and not the
* READ permission.
*/
public void clearNonPublicFields() {
this.email = null;
}
}
@@ -36,6 +36,7 @@ import com.sap.sse.security.Action;
import com.sap.sse.security.SecurityService;
import com.sap.sse.security.interfaces.Credential;
import com.sap.sse.security.shared.AccessControlListAnnotation;
import com.sap.sse.security.shared.HasPermissions;
import com.sap.sse.security.shared.HasPermissions.DefaultActions;
import com.sap.sse.security.shared.OwnershipAnnotation;
import com.sap.sse.security.shared.QualifiedObjectIdentifier;
@@ -204,13 +205,10 @@ public class UserManagementServiceImpl extends RemoteServiceServlet implements U
@Override
public OwnershipDTO setOwnership(final String username, final UUID userGroupId,
final QualifiedObjectIdentifier idOfOwnedObject, final String displayNameOfOwnedObject) {
SecurityUtils.getSubject()
.checkPermission(idOfOwnedObject.getStringPermission(DefaultActions.CHANGE_OWNERSHIP));
final User user = getSecurityService().getUserByName(username);
// no security check if current user can see the user associated with the given username
final Ownership result = getSecurityService().setOwnership(idOfOwnedObject, user,
getSecurityService().getUserGroup(userGroupId), displayNameOfOwnedObject);
return securityDTOFactory.createOwnershipDTO(result, new HashMap<>(), new HashMap<>());
@@ -452,18 +450,10 @@ public class UserManagementServiceImpl extends RemoteServiceServlet implements U
@Override
public Collection<UserDTO> getUserList() throws UnauthorizedException {
List<UserDTO> users = new ArrayList<>();
for (User u : getSecurityService().getUserList()) {
if (SecurityUtils.getSubject()
.isPermitted(SecuredSecurityTypes.USER.getStringPermissionForObject(DefaultActions.READ, u))
|| SecurityUtils.getSubject().isPermitted(SecuredSecurityTypes.USER
.getStringPermissionForObject(SecuredSecurityTypes.PublicReadableActions.READ_PUBLIC, u))) {
// TODO: pruning if subject only has READ_PUBLIC permission
final UserDTO userDTO = getUserDTOWithFilteredRolesAndPermissions(u);
users.add(userDTO);
}
}
return users;
final HasPermissions.Action[] requiredActionsForRead = SecuredSecurityTypes.PublicReadableActions.READ_AND_READ_PUBLIC_ACTIONS;
return getSecurityService().mapAndFilterByAnyExplicitPermissionForCurrentUser(SecuredSecurityTypes.USER,
requiredActionsForRead, getSecurityService().getUserList(),
this::getUserDTOWithFilteredRolesAndPermissions);
}
@Override
@@ -1110,7 +1100,7 @@ public class UserManagementServiceImpl extends RemoteServiceServlet implements U
* user can actually see.
*/
private UserDTO getUserDTOWithFilteredRolesAndPermissions(final User user) {
return securityDTOFactory.createUserDTOFromUser(user, getSecurityService(), permission -> {
final UserDTO result = securityDTOFactory.createUserDTOFromUser(user, getSecurityService(), permission -> {
final TypeRelativeObjectIdentifier typeRelativeObjectIdentifier = PermissionAndRoleAssociation
.get(permission, user);
return SecurityUtils.getSubject().isPermitted(SecuredSecurityTypes.PERMISSION_ASSOCIATION
@@ -1121,6 +1111,10 @@ public class UserManagementServiceImpl extends RemoteServiceServlet implements U
return SecurityUtils.getSubject().isPermitted(SecuredSecurityTypes.ROLE_ASSOCIATION
.getStringPermissionForTypeRelativeIdentifier(DefaultActions.READ, typeRelativeObjectIdentifier));
});
if (!getSecurityService().hasCurrentUserReadPermission(user)) {
result.clearNonPublicFields();
}
return result;
}
@Override
@@ -2,6 +2,7 @@ package com.sap.sse.security.jaxrs.api;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
@@ -13,6 +14,7 @@ import javax.ws.rs.PUT;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.QueryParam;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import javax.ws.rs.core.Response.Status;
@@ -101,12 +103,24 @@ public class OwnershipResource extends AbstractSecurityResource {
@Produces("application/json;charset=UTF-8")
public Response getOwnership(@PathParam("objectType") String objectType,
@PathParam("typeRelativeObjectId") String typeRelativeObjectId) throws OwnershipException {
return getOwnership(objectType, new String[] { typeRelativeObjectId });
}
@Path("{objectType}")
@GET
@Produces("application/json;charset=UTF-8")
public Response getOwnershipWithMultiId(@PathParam("objectType") String objectType,
@QueryParam("id") List<String> compositeTypeRelativeObjectId) throws OwnershipException {
return getOwnership(objectType, compositeTypeRelativeObjectId.toArray(new String[0]));
}
private Response getOwnership(String objectType, final String[] typeRelativeObjectIdArray) {
QualifiedObjectIdentifier identifier = new QualifiedObjectIdentifierImpl(objectType,
new TypeRelativeObjectIdentifier(typeRelativeObjectId));
new TypeRelativeObjectIdentifier(typeRelativeObjectIdArray));
final OwnershipAnnotation existingOwnership = getService().getOwnership(identifier);
final JSONObject result = new JSONObject();
result.put(KEY_OBJECT_TYPE, objectType);
result.put(KEY_OBJECT_ID, typeRelativeObjectId);
result.put(KEY_OBJECT_ID, identifier.getTypeRelativeObjectIdentifier());
result.put(KEY_GROUP_ID, existingOwnership == null || existingOwnership.getAnnotation().getTenantOwner() == null ? null : existingOwnership.getAnnotation().getTenantOwner().getId().toString());
result.put(KEY_USERNAME, existingOwnership == null || existingOwnership.getAnnotation().getUserOwner() == null ? null : existingOwnership.getAnnotation().getUserOwner().getName());
result.put(KEY_DISPLAY_NAME, existingOwnership == null || existingOwnership.getDisplayNameOfAnnotatedObject() == null ? null : existingOwnership.getDisplayNameOfAnnotatedObject());
@@ -9,7 +9,7 @@
</head>
<body>
<h1>SAP Sponsorships Engine Security Webservices API</h1>
<h2>URL: /api/restsecurity/onwership</h2>
<h2>URL: /api/restsecurity/ownership</h2>
<b>Description:</b>
<p>The service obtains or changes the ownership of object, or obtains or changes access control list (ACL) properties of an object.</p>
@@ -70,6 +70,30 @@
Will provide a JSON document as explained above.</td>
</tr>
<tr>
<td>Request Method:</td>
<td>GET /{objectType}?id={typeRelativeObjectIdPart1}&id={typeRelativeObjectIdPart2}&...</td>
</tr>
<tr>
<td>Output format:</td>
<td>a JSON document of the following format<br>
<pre>{"objectType":"USER_GROUP","objectId":"82832851-07ac-47ee-9ddf-6f4f9eaa7823","groupId":"82832851-07ac-47ee-9ddf-6f4f9eaa7823","username":"admin"}</pre>
</td>
</tr>
<tr>
<td>Parameter (path)</td>
<td>
<div>objectType</div> Object type represents the type of object to change the ownership.
<div>id</div> Can be used multiple times, e.g., in order to encode a composite type-relative object ID such as they
are used for objects of type TRACKED_RACE.
</td>
</tr>
<tr>
<td>Example:</td>
<td><code>curl "http://127.0.0.1:8888/security/api/restsecurity/ownership/TRACKED_RACE?id=Croatia%20Coast%20Cup%202019%20-%20ORC%20with%20Spinnaker&id=Race%201%20-%20ORC%20mit%20Spi"</code><br>
Will provide a JSON document as explained above.</td>
</tr>
<tr>
<td>Request Method:</td>
<td>GET /{objectType}/{typeRelativeObjectId}/acl</td>
+1 -1
View File
@@ -8,7 +8,7 @@ handlers= java.util.logging.FileHandler, java.util.logging.ConsoleHandler
java.util.logging.FileHandler.level = ALL
java.util.logging.FileHandler.pattern = logs/sailing%u.log
java.util.logging.FileHandler.limit = 500000000
java.util.logging.FileHandler.count = 10
java.util.logging.FileHandler.count = 50
java.util.logging.FileHandler.formatter = java.util.logging.SimpleFormatter
# consoleHandler specific properties