diff options
author | 2019-01-04 13:44:03 -0500 | |
---|---|---|
committer | 2019-01-04 13:44:11 -0500 | |
commit | 536c6aabdfd2bcdc493501a9498fb8a97d208c0b (patch) | |
tree | 52e32020ce8eeabb2ba745c5ba275bd7ae82c99e /src/main | |
parent | 297ea699d8f7f3be96abea6c28e4204f7c4687a4 (diff) |
Patch set 2: changes to MR_Client
Also introduces new AAF API call (userRoles)
Change-Id: I9861fe7f3339ced504f006da7aaa159a3cd67b70
Signed-off-by: dglFromAtt <dgl@research.att.com>
Issue-ID: DMAAP-856
Diffstat (limited to 'src/main')
10 files changed, 209 insertions, 23 deletions
diff --git a/src/main/java/org/onap/dmaap/dbcapi/aaf/AafService.java b/src/main/java/org/onap/dmaap/dbcapi/aaf/AafService.java index 4778aff..253ad11 100644 --- a/src/main/java/org/onap/dmaap/dbcapi/aaf/AafService.java +++ b/src/main/java/org/onap/dmaap/dbcapi/aaf/AafService.java @@ -112,6 +112,10 @@ public class AafService extends BaseLoggingClass { logger.info( "entry: addGrant() " ); return doPost( grant, "authz/role/perm", 201 ); } + public int addUserRole( AafUserRole ur ) { + logger.info( "entry: addUserRole() " ); + return doPost( ur, "authz/userRole", 201 ); + } public int delGrant( DmaapGrant grant ) { int rc = -1; diff --git a/src/main/java/org/onap/dmaap/dbcapi/aaf/AafUserRole.java b/src/main/java/org/onap/dmaap/dbcapi/aaf/AafUserRole.java new file mode 100644 index 0000000..7b4f882 --- /dev/null +++ b/src/main/java/org/onap/dmaap/dbcapi/aaf/AafUserRole.java @@ -0,0 +1,69 @@ +/*- + * ============LICENSE_START======================================================= + * org.onap.dmaap + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed 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. + * ============LICENSE_END========================================================= + */ + +package org.onap.dmaap.dbcapi.aaf; + +import org.apache.log4j.Logger; + + +public class AafUserRole extends AafObject { + static final Logger logger = Logger.getLogger(AafUserRole.class); + + private String identity; + private String role; + + + + public AafUserRole(String identity, String role ) { + super(); + this.identity = identity; + this.role = role; + } + + public void setRole(String role) { + this.role = role; + } + public String getRole() { + return role; + } + + public String getIdentity() { + return identity; + } + + public void setIdentity(String identity) { + this.identity = identity; + } + + public String toJSON() { + + String postJSON = String.format(" { \"user\": \"%s\", \"role\": \"%s\" }", + this.getIdentity(), + this.getRole() + ); + logger.info( "returning JSON: " + postJSON); + + return postJSON; + } + + + + +} diff --git a/src/main/java/org/onap/dmaap/dbcapi/model/DmaapObject.java b/src/main/java/org/onap/dmaap/dbcapi/model/DmaapObject.java index 8e804b2..1b3f824 100644 --- a/src/main/java/org/onap/dmaap/dbcapi/model/DmaapObject.java +++ b/src/main/java/org/onap/dmaap/dbcapi/model/DmaapObject.java @@ -30,8 +30,11 @@ import javax.xml.bind.annotation.XmlRootElement; import org.onap.dmaap.dbcapi.logging.BaseLoggingClass; +import io.swagger.annotations.ApiModelProperty; + @XmlRootElement public abstract class DmaapObject extends BaseLoggingClass { + @ApiModelProperty( value = "datestamp for last update to this object") protected Date lastMod; protected DmaapObject_Status status; @@ -81,6 +84,7 @@ public abstract class DmaapObject extends BaseLoggingClass { } } + @ApiModelProperty( hidden=true ) public boolean isStatusValid() { if ( this.status == DmaapObject_Status.VALID ) { return true; diff --git a/src/main/java/org/onap/dmaap/dbcapi/model/MR_Client.java b/src/main/java/org/onap/dmaap/dbcapi/model/MR_Client.java index 580800c..f182fd6 100644 --- a/src/main/java/org/onap/dmaap/dbcapi/model/MR_Client.java +++ b/src/main/java/org/onap/dmaap/dbcapi/model/MR_Client.java @@ -26,15 +26,25 @@ import javax.xml.bind.annotation.XmlRootElement; import org.onap.dmaap.dbcapi.database.DatabaseClass; +import io.swagger.annotations.ApiModelProperty; + @XmlRootElement public class MR_Client extends DmaapObject { + @ApiModelProperty( value="a tag indicating a logical deployment site") private String dcaeLocationName; + @ApiModelProperty( value="the URL for a MR instance - typically in the same dcaeLocation - that this client should use to access the topic") private String topicURL; + @ApiModelProperty( value="Fully Qualified Topic Name constructed by dbcapi") private String fqtn; + @ApiModelProperty( value="an AAF Role to be granted an appropriate Permission. If specified, takes precedence over clientIdentity, for backwards compatibility.") private String clientRole; + @ApiModelProperty( value="one or more actions from the set (\"pub\", \"sub\", \"view\") for which this client needs Permission") private String[] action; + @ApiModelProperty( value="a unique identifier generated by dbcapi for this client") private String mrClientId; + @ApiModelProperty( value="an AAF identity to be associated to an appropriate topic Role") + private String clientIdentity; public MR_Client() { @@ -97,7 +107,24 @@ public class MR_Client extends DmaapObject { public void setAction(String[] action) { this.action = action; } - + + @ApiModelProperty( hidden=true ) + public boolean isPublisher() { + return hasAction( "pub"); + } + @ApiModelProperty( hidden=true ) + public boolean isSubscriber() { + return hasAction( "sub"); + } + + public boolean hasAction( String val ) { + for (String s: this.action) { + if ( s!= null && s.equals(val)) { + return true; + } + } + return false; + } public String getMrClientId() { return mrClientId; } @@ -115,5 +142,21 @@ public class MR_Client extends DmaapObject { public void setTopicURL(String topicURL) { this.topicURL = topicURL; } + + public String getClientIdentity() { + return clientIdentity; + } + + public void setClientIdentity(String clientIdentity) { + this.clientIdentity = clientIdentity; + } + public boolean hasClientIdentity() { + if ( this.clientIdentity == null || this.clientIdentity.isEmpty() ) { + return false; + } else { + return true; + } + } + } diff --git a/src/main/java/org/onap/dmaap/dbcapi/model/Topic.java b/src/main/java/org/onap/dmaap/dbcapi/model/Topic.java index bfd948b..7eea5f1 100644 --- a/src/main/java/org/onap/dmaap/dbcapi/model/Topic.java +++ b/src/main/java/org/onap/dmaap/dbcapi/model/Topic.java @@ -30,6 +30,8 @@ import javax.xml.bind.annotation.XmlRootElement; import org.onap.dmaap.dbcapi.util.DmaapConfig; +import io.swagger.annotations.ApiModelProperty; + import org.onap.dmaap.dbcapi.service.DmaapService; import org.onap.dmaap.dbcapi.service.TopicService; @@ -37,22 +39,36 @@ import org.onap.dmaap.dbcapi.service.TopicService; @XmlRootElement public class Topic extends DmaapObject { + @ApiModelProperty( value="Fully Qualified Topic Name constructed by dbcapi, following the rules for `fqtnStyle`") private String fqtn; + @ApiModelProperty( value="the short name used by humans, and utilized to construct the `FQTN`") private String topicName; + @ApiModelProperty( value="a description of what this Topic is used for") private String topicDescription; private String tnxEnabled; + @ApiModelProperty( value="a label used to identify who requested this `Topic` to be provisioned. In the future this " + + "may be an AAF Identity.") private String owner; + @ApiModelProperty( value="a reference to an identifier that describes a data format used for this `Topic`") private String formatUuid; + @ApiModelProperty( value="An indicator for how this `Topic` should be replicated when there are more than one `MR_Cluster` instances") private ReplicationType replicationCase; + @ApiModelProperty( value="the URL of an outside MR instance") private String globalMrURL; // optional: URL of global MR to replicate to/from + @ApiModelProperty( value="the construction rule for the `fqtn` field") private FqtnType fqtnStyle; - private String version; + @ApiModelProperty( value="a hook for any versioning needed for managing a `Topic` over time") + private String version; + @ApiModelProperty( value="the kafka attribute for specifying the number of partitions") private String partitionCount; + @ApiModelProperty( value="the kafka attribute for specifying replication within an `MR_Cluster` instance") private String replicationCount; + @ApiModelProperty( value="a value generated by dbcapi, this AAF Role has permission to publish to this `Topic`") private String publisherRole; + @ApiModelProperty( value="a value generated by dbcapi, this AAF Role has permission to subscribe to this `Topic`") private String subscriberRole; - + @ApiModelProperty( value="an array of `MR_Client` objects associated to this `Topic`") private ArrayList<MR_Client> clients; @@ -222,6 +238,7 @@ public class Topic extends DmaapObject { return clients; } + @ApiModelProperty( hidden=true ) public int getNumClients() { if ( this.clients == null ) { return 0; @@ -311,7 +328,7 @@ public class Topic extends DmaapObject { logger.info( str.toString() ); return str.toString(); } - + @ApiModelProperty( hidden=true ) public byte[] getBytes() { return toProvJSON().getBytes(StandardCharsets.UTF_8); } diff --git a/src/main/java/org/onap/dmaap/dbcapi/resources/MR_ClientResource.java b/src/main/java/org/onap/dmaap/dbcapi/resources/MR_ClientResource.java index 1ca4a53..a621338 100644 --- a/src/main/java/org/onap/dmaap/dbcapi/resources/MR_ClientResource.java +++ b/src/main/java/org/onap/dmaap/dbcapi/resources/MR_ClientResource.java @@ -79,8 +79,11 @@ public class MR_ClientResource extends BaseLoggingClass { } @POST - @ApiOperation( value = "return MR_Client details", - notes = "Create a `MR_Client` object.", + @ApiOperation( value = "Associate an MR_Client object to a Topic", + notes = "Create a `MR_Client` object." + + "The `dcaeLocation` attribute is used to match an `MR_Cluster` object with the same value, with the intent of localizing message traffic." + + " In legacy implementation, the `clientRole` is granted appropriate permission in AAF." + + " Newer implementions may instead specify an AAF Identity, which will be added to the appropriate `Topic` role.", response = MR_Client.class) @ApiResponses( value = { @ApiResponse( code = 200, message = "Success", response = MR_Client.class), @@ -94,7 +97,11 @@ public class MR_ClientResource extends BaseLoggingClass { try { resp.required( "fqtn", client.getFqtn(), ""); resp.required( "dcaeLocationName", client.getDcaeLocationName(), ""); - resp.required( "clientRole", client.getClientRole(), "" ); + String s = client.getClientRole(); + if ( s == null ) { + s = client.getClientIdentity(); + } + resp.required( "clientRole or clientIdentity", s, "" ); resp.required( "action", client.getAction(), ""); } catch ( RequiredFieldException rfe ) { @@ -139,7 +146,7 @@ public class MR_ClientResource extends BaseLoggingClass { } @PUT - @ApiOperation( value = "return MR_Client details", + @ApiOperation( value = "Update an MR_Client object", notes = "Update a `MR_Client` object, specified by clientId", response = MR_Client.class) @ApiResponses( value = { @@ -175,7 +182,7 @@ public class MR_ClientResource extends BaseLoggingClass { } @DELETE - @ApiOperation( value = "return MR_Client details", + @ApiOperation( value = "Delete an MR_Client object", notes = "Delete a `MR_Client` object, specified by clientId", response = MR_Client.class) @ApiResponses( value = { diff --git a/src/main/java/org/onap/dmaap/dbcapi/resources/TopicResource.java b/src/main/java/org/onap/dmaap/dbcapi/resources/TopicResource.java index 5f027aa..be1b3ac 100644 --- a/src/main/java/org/onap/dmaap/dbcapi/resources/TopicResource.java +++ b/src/main/java/org/onap/dmaap/dbcapi/resources/TopicResource.java @@ -91,8 +91,11 @@ public class TopicResource extends BaseLoggingClass { } @POST - @ApiOperation( value = "return Topic details", - notes = "Create `Topic` object.", + @ApiOperation( value = "Create a Topic object", + notes = "Create `Topic` object." + + "For convenience, the message body may populate the `clients` array, in which case each entry will be added as an `MR_Client`." + + " Beginning in ONAP Dublin Release, dbcapi will create two AAF Roles by default, one each for the publisher and subscriber per topic." + + " MR_Clients can then specify an AAF Identity to be added to the appropriate default Role, avoiding the need to create Role(s) in advance.", response = Topic.class) @ApiResponses( value = { @ApiResponse( code = 200, message = "Success", response = Topic.class), diff --git a/src/main/java/org/onap/dmaap/dbcapi/service/MR_ClientService.java b/src/main/java/org/onap/dmaap/dbcapi/service/MR_ClientService.java index 5bd62cb..186a003 100644 --- a/src/main/java/org/onap/dmaap/dbcapi/service/MR_ClientService.java +++ b/src/main/java/org/onap/dmaap/dbcapi/service/MR_ClientService.java @@ -38,6 +38,7 @@ import org.onap.dmaap.dbcapi.aaf.AafService; import org.onap.dmaap.dbcapi.aaf.DmaapGrant; import org.onap.dmaap.dbcapi.aaf.DmaapPerm; import org.onap.dmaap.dbcapi.aaf.AafService.ServiceType; +import org.onap.dmaap.dbcapi.aaf.AafUserRole; import org.onap.dmaap.dbcapi.client.MrProvConnection; import org.onap.dmaap.dbcapi.database.DatabaseClass; import org.onap.dmaap.dbcapi.logging.BaseLoggingClass; @@ -128,7 +129,22 @@ public class MR_ClientService extends BaseLoggingClass{ logger.info( "Client dcaeLocation that doesn't exist or not specified" ); return null; } - grantClientPerms( client, err); + // original style: clients specified Role. This has precedence for backwards + // compatibility. + // ONAP style: clients specify Identity to be assigned to generated Role + String role = client.getClientRole(); + if ( role != null ) { + grantClientRolePerms( client, err); + } else if ( client.hasClientIdentity() ){ + if ( client.isSubscriber() ) { + role = topic.getSubscriberRole(); + assignIdentityToRole( client, role, err ); + } + if (client.isPublisher() ) { + role = topic.getPublisherRole(); + assignIdentityToRole( client, role, err ); + } + } if ( ! client.isStatusValid()) { return null; } @@ -189,26 +205,46 @@ public class MR_ClientService extends BaseLoggingClass{ return DmaapObject_Status.INVALID; } - private void grantClientPerms( MR_Client client, ApiError err) { + private void grantClientRolePerms( MR_Client client, ApiError err) { AafService aaf = new AafService(ServiceType.AAF_TopicMgr); String instance = ":topic." + client.getFqtn(); client.setStatus( DmaapObject_Status.VALID); + String role = client.getClientRole(); for( String want : client.getAction() ) { int rc; DmaapPerm perm = new DmaapPerm( dmaap.getTopicPerm(), instance, want ); - DmaapGrant g = new DmaapGrant( perm, client.getClientRole() ); - rc = aaf.addGrant( g ); - if ( rc != 201 && rc != 409 ) { - client.setStatus( DmaapObject_Status.INVALID); - err.setCode(rc); - err.setMessage( "Grant of " + dmaap.getTopicPerm() + "|" + instance + "|" + want + " failed for " + client.getClientRole() ); - logger.warn( err.getMessage()); - return; - } + if ( role != null ) { + DmaapGrant g = new DmaapGrant( perm, role ); + rc = aaf.addGrant( g ); + if ( rc != 201 && rc != 409 ) { + client.setStatus( DmaapObject_Status.INVALID); + err.setCode(rc); + err.setMessage( "Grant of " + dmaap.getTopicPerm() + "|" + instance + "|" + want + " failed for " + role ); + logger.warn( err.getMessage()); + return; + } + } else { + logger.warn( "No Grant of " + dmaap.getTopicPerm() + "|" + instance + "|" + want + " because role is null " ); + } } } + private void assignIdentityToRole( MR_Client client, String role, ApiError err ) { + AafService aaf = new AafService(ServiceType.AAF_TopicMgr); + + AafUserRole ur = new AafUserRole( client.getClientIdentity(), role ); + int rc = aaf.addUserRole( ur ); + if ( rc != 201 && rc != 409 ) { + client.setStatus( DmaapObject_Status.INVALID); + err.setCode(rc); + err.setMessage( "Failed to add user " + client.getClientIdentity()+ " to " + role ); + logger.warn( err.getMessage()); + return; + } + client.setStatus( DmaapObject_Status.VALID); + + } private void revokeClientPerms( MR_Client client, ApiError err) { AafService aaf = new AafService(ServiceType.AAF_TopicMgr); diff --git a/src/main/java/org/onap/dmaap/dbcapi/service/TopicService.java b/src/main/java/org/onap/dmaap/dbcapi/service/TopicService.java index a26205c..cfec54e 100644 --- a/src/main/java/org/onap/dmaap/dbcapi/service/TopicService.java +++ b/src/main/java/org/onap/dmaap/dbcapi/service/TopicService.java @@ -61,7 +61,6 @@ public class TopicService extends BaseLoggingClass { private Map<String, Topic> mr_topics = DatabaseClass.getTopics(); private static DmaapService dmaapSvc = new DmaapService(); - private static Dmaap dmaap = new DmaapService().getDmaap(); private MR_ClientService clientService = new MR_ClientService(); private MR_ClusterService clusters = new MR_ClusterService(); private DcaeLocationService locations = new DcaeLocationService(); @@ -258,6 +257,7 @@ public class TopicService extends BaseLoggingClass { logger.info( "c fqtn=" + c.getFqtn() + " ID=" + c.getMrClientId() + " url=" + c.getTopicURL()); MR_Client nc = new MR_Client( c.getDcaeLocationName(), topic.getFqtn(), c.getClientRole(), c.getAction()); nc.setFqtn(topic.getFqtn()); + nc.setClientIdentity( c.getClientIdentity()); logger.info( "nc fqtn=" + nc.getFqtn() + " ID=" + nc.getMrClientId() + " url=" + nc.getTopicURL()); clients2.add( clientService.addMr_Client(nc, topic, err)); if ( ! err.is2xx()) { diff --git a/src/main/resources/schema_11.sql b/src/main/resources/schema_11.sql index de848b1..3bf7b1f 100644 --- a/src/main/resources/schema_11.sql +++ b/src/main/resources/schema_11.sql @@ -23,5 +23,8 @@ add column publisher_role varchar(100), add column subscriber_role varchar(100) ; +@alter table mr_client + add column client_identity varchar(100) +; update dmaapbc_sch_ver set version = 11 where version = 10; |