Merge branch 'master' of https://gitlab.com/entgra/carbon-device-mgt into application-mgt-new

feature/appm-store/pbac
Charitha Goonetilleke 5 years ago
commit 4e9628dff4

@ -27,6 +27,8 @@ import org.wso2.carbon.apimgt.application.extension.api.util.RegistrationProfile
import org.wso2.carbon.apimgt.application.extension.constants.ApiApplicationConstants;
import org.wso2.carbon.apimgt.application.extension.dto.ApiApplicationKey;
import org.wso2.carbon.apimgt.application.extension.exception.APIManagerException;
import org.wso2.carbon.apimgt.integration.client.OAuthRequestInterceptor;
import org.wso2.carbon.apimgt.integration.client.store.StoreClient;
import org.wso2.carbon.base.MultitenantConstants;
import org.wso2.carbon.context.PrivilegedCarbonContext;
import org.wso2.carbon.device.mgt.common.exceptions.DeviceManagementException;
@ -94,9 +96,8 @@ public class ApiApplicationRegistrationServiceImpl implements ApiApplicationRegi
return Response.status(Response.Status.NOT_ACCEPTABLE).entity("APIs(Tags) are not allowed to this user."
).build();
}
PrivilegedCarbonContext.getThreadLocalCarbonContext().setUsername(PrivilegedCarbonContext.
getThreadLocalCarbonContext().getUserRealm().getRealmConfiguration().getAdminUserName());
String username = APIUtil.getAuthenticatedUser();
APIManagementProviderService apiManagementProviderService = APIUtil.getAPIManagementProviderService();
String validityPeriod;
if (registrationProfile.getValidityPeriod() == null) {
@ -106,6 +107,22 @@ public class ApiApplicationRegistrationServiceImpl implements ApiApplicationRegi
}
String applicationName = registrationProfile.getApplicationName();
if (username.equals(registrationProfile.getUsername())) {
synchronized (ApiApplicationRegistrationServiceImpl.class) {
StoreClient storeClient = new StoreClient(new OAuthRequestInterceptor(registrationProfile.getUsername(),
registrationProfile.getPassword()));
ApiApplicationKey apiApplicationKey = apiManagementProviderService.generateAndRetrieveApplicationKeys(
applicationName, registrationProfile.getTags(),
ApiApplicationConstants.DEFAULT_TOKEN_TYPE, username,
registrationProfile.isAllowedToAllDomains(), validityPeriod, storeClient);
return Response.status(Response.Status.CREATED).entity(apiApplicationKey.toString()).build();
}
}
PrivilegedCarbonContext.getThreadLocalCarbonContext().setUsername(PrivilegedCarbonContext.
getThreadLocalCarbonContext().getUserRealm().getRealmConfiguration().getAdminUserName());
synchronized (ApiApplicationRegistrationServiceImpl.class) {
ApiApplicationKey apiApplicationKey = apiManagementProviderService.generateAndRetrieveApplicationKeys(
applicationName, registrationProfile.getTags(),

@ -32,6 +32,10 @@ import javax.xml.bind.annotation.XmlRootElement;
public class RegistrationProfile {
@XmlElement(required = true)
private String applicationName;
@XmlElement
private String username;
@XmlElement
private String password;
@XmlElement(required = true)
private String tags[];
@XmlElement(required = true)
@ -70,4 +74,20 @@ public class RegistrationProfile {
public void setValidityPeriod(String validityPeriod) {
this.validityPeriod = validityPeriod;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
}

@ -20,6 +20,7 @@ package org.wso2.carbon.apimgt.application.extension;
import org.wso2.carbon.apimgt.application.extension.dto.ApiApplicationKey;
import org.wso2.carbon.apimgt.application.extension.exception.APIManagerException;
import org.wso2.carbon.apimgt.integration.client.store.StoreClient;
/**
* This comprise on operation that is been done with api manager from CDMF. This service needs to be implemented in APIM.
@ -49,6 +50,28 @@ public interface APIManagementProviderService {
String keyType, String username, boolean isAllowedAllDomains,
String validityTime) throws APIManagerException;
/**
* Generate and retreive application keys. if the application does exist then
* create it and subscribe to apis that are grouped with the tags.
*
* @param apiApplicationName name of the application.
* @param tags tags of the apis that application needs to be subscribed.
* @param keyType of the application.
* @param username to whom the application is created
* @param isAllowedAllDomains application is allowed to all the tenants
* @param validityTime validity period of the application
* @param storeClient Specified store client
* @return consumerkey and secrete of the created application.
* @throws APIManagerException
*/
ApiApplicationKey generateAndRetrieveApplicationKeys(String apiApplicationName,
String tags[],
String keyType,
String username,
boolean isAllowedAllDomains,
String validityTime,
StoreClient storeClient) throws APIManagerException;
/**
* Remove APIM Application.
*/

@ -94,11 +94,18 @@ public class APIManagementProviderServiceImpl implements APIManagementProviderSe
@Override
public synchronized ApiApplicationKey generateAndRetrieveApplicationKeys(String applicationName, String tags[],
String keyType, String username,
boolean isAllowedAllDomains, String validityTime)
throws APIManagerException {
StoreClient storeClient =
APIApplicationManagerExtensionDataHolder.getInstance().getIntegrationClientService()
.getStoreClient();
boolean isAllowedAllDomains, String validityTime,
StoreClient sClient) throws APIManagerException {
StoreClient storeClient;
if (sClient == null) {
storeClient = APIApplicationManagerExtensionDataHolder.getInstance().getIntegrationClientService()
.getStoreClient();
} else {
storeClient = sClient;
}
String tenantDomain = PrivilegedCarbonContext.getThreadLocalCarbonContext()
.getTenantDomain();
try {
@ -211,4 +218,16 @@ public class APIManagementProviderServiceImpl implements APIManagementProviderSe
}
}
/**
* {@inheritDoc}
*/
@Override
public synchronized ApiApplicationKey generateAndRetrieveApplicationKeys(String applicationName, String tags[],
String keyType, String username,
boolean isAllowedAllDomains,
String validityTime)
throws APIManagerException {
return this.generateAndRetrieveApplicationKeys(applicationName, tags, keyType, username,
isAllowedAllDomains, validityTime, null);
}
}

@ -36,6 +36,12 @@ public class IntegrationClientServiceImpl implements IntegrationClientService {
publisherClient = new PublisherClient(oAuthRequestInterceptor);
}
public IntegrationClientServiceImpl(OAuthRequestInterceptor oAuthRequestInterceptor) {
this.oAuthRequestInterceptor = oAuthRequestInterceptor;
storeClient = new StoreClient(oAuthRequestInterceptor);
publisherClient = new PublisherClient(oAuthRequestInterceptor);
}
public static IntegrationClientServiceImpl getInstance() {
if (instance == null) {
synchronized (IntegrationClientService.class) {

@ -56,7 +56,7 @@ public class OAuthRequestInterceptor implements RequestInterceptor {
private static final String APIM_SUBSCRIBE_SCOPE = "apim:subscribe";
private static final long DEFAULT_REFRESH_TIME_OFFSET_IN_MILLIS = 100000;
private DCRClient dcrClient;
private static OAuthApplication oAuthApplication;
private OAuthApplication oAuthApplication;
private static Map<String, AccessTokenInfo> tenantUserTokenMap = new ConcurrentHashMap<>();
private static final Log log = LogFactory.getLog(OAuthRequestInterceptor.class);
@ -67,8 +67,15 @@ public class OAuthRequestInterceptor implements RequestInterceptor {
String username = APIMConfigReader.getInstance().getConfig().getUsername();
String password = APIMConfigReader.getInstance().getConfig().getPassword();
dcrClient = Feign.builder().client(new OkHttpClient(Utils.getSSLClient())).logger(new Slf4jLogger())
.logLevel(Logger.Level.FULL).requestInterceptor(new BasicAuthRequestInterceptor(username,
password))
.logLevel(Logger.Level.FULL).requestInterceptor(new BasicAuthRequestInterceptor(username, password))
.contract(new JAXRSContract()).encoder(new GsonEncoder()).decoder(new GsonDecoder())
.target(DCRClient.class, Utils.replaceProperties(
APIMConfigReader.getInstance().getConfig().getDcrEndpoint()));
}
public OAuthRequestInterceptor(String username, String password) {
dcrClient = Feign.builder().client(new OkHttpClient(Utils.getSSLClient())).logger(new Slf4jLogger())
.logLevel(Logger.Level.FULL).requestInterceptor(new BasicAuthRequestInterceptor(username, password))
.contract(new JAXRSContract()).encoder(new GsonEncoder()).decoder(new GsonDecoder())
.target(DCRClient.class, Utils.replaceProperties(
APIMConfigReader.getInstance().getConfig().getDcrEndpoint()));
@ -82,7 +89,11 @@ public class OAuthRequestInterceptor implements RequestInterceptor {
clientProfile.setClientName(APPLICATION_NAME);
clientProfile.setCallbackUrl("");
clientProfile.setGrantType(GRANT_TYPES);
clientProfile.setOwner(APIMConfigReader.getInstance().getConfig().getUsername());
String username = PrivilegedCarbonContext.getThreadLocalCarbonContext().getUsername();
if (username == null || username.isEmpty()) {
username = APIMConfigReader.getInstance().getConfig().getUsername();
}
clientProfile.setOwner(username);
clientProfile.setSaasApp(true);
oAuthApplication = dcrClient.register(clientProfile);
}
@ -100,8 +111,7 @@ public class OAuthRequestInterceptor implements RequestInterceptor {
JWTClient jwtClient = APIIntegrationClientDataHolder.getInstance().getJwtClientManagerService()
.getJWTClient();
tenantBasedAccessTokenInfo = jwtClient.getAccessToken(oAuthApplication.getClientId(),
oAuthApplication.getClientSecret(), username,
REQUIRED_SCOPE);
oAuthApplication.getClientSecret(), username, REQUIRED_SCOPE);
tenantBasedAccessTokenInfo.setExpiresIn(
System.currentTimeMillis() + (tenantBasedAccessTokenInfo.getExpiresIn() * 1000));
if (tenantBasedAccessTokenInfo.getScopes() == null) {

@ -54,7 +54,7 @@ public class APIPublisherServiceTest extends BaseAPIPublisherTest {
@BeforeTest
public void initialConfigs() throws Exception {
initializeOAuthApplication();
//initializeOAuthApplication();
WebappPublisherConfig.init();
}

@ -115,6 +115,7 @@ public class UserManagementServiceImpl implements UserManagementService {
private static final Log log = LogFactory.getLog(UserManagementServiceImpl.class);
private static final String DEFAULT_DEVICE_USER = "Internal/devicemgt-user";
private static final String DEFAULT_SUBSCRIBER = "Internal/subscriber";
// Permissions that are given for a normal device user.
private static final Permission[] PERMISSIONS_FOR_DEVICE_USER = {
@ -158,9 +159,31 @@ public class UserManagementServiceImpl implements UserManagementService {
List<String> tmpRoles = new ArrayList<>();
String[] userInfoRoles = userInfo.getRoles();
tmpRoles.add(DEFAULT_DEVICE_USER);
boolean subscriberFound = false;
if (userInfoRoles != null) {
//check if subscriber role is coming in the payload
for (String r : userInfoRoles) {
if (DEFAULT_SUBSCRIBER.equals(r)) {
subscriberFound = true;
break;
}
}
tmpRoles.addAll(Arrays.asList(userInfoRoles));
}
if (!subscriberFound) {
// Add Internal/subscriber role to new users
if (userStoreManager.isExistingRole(DEFAULT_SUBSCRIBER)) {
tmpRoles.add(DEFAULT_SUBSCRIBER);
} else {
log.warn("User: " + userInfo.getUsername() + " will not be able to enroll devices as '" +
DEFAULT_SUBSCRIBER + "' is missing in the system");
}
}
String[] roles = new String[tmpRoles.size()];
tmpRoles.toArray(roles);

@ -40,8 +40,12 @@ public class GroupManagementAdminServiceImpl implements GroupManagementAdminServ
try {
RequestValidationUtil.validatePaginationParameters(offset, limit);
GroupPaginationRequest request = new GroupPaginationRequest(offset, limit);
request.setGroupName(name.toUpperCase());
request.setOwner(owner.toUpperCase());
if (name != null){
request.setGroupName(name.toUpperCase());
}
if (owner != null) {
request.setOwner(owner.toUpperCase());
}
PaginationResult deviceGroupsResult = DeviceMgtAPIUtils.getGroupManagementProviderService()
.getGroups(request);
DeviceGroupList deviceGroupList = new DeviceGroupList();

@ -98,14 +98,15 @@
<div class="row">
<div class="dontfloat feature-wrapper" name ="deviceFeature">
<div class="col-xs-3">
<input type="text" class="form-control" id="feature-name" placeholder="name" value="{{this.name}}"/>
<input type="text" class="form-control feature-name" placeholder="name" value="{{this.name}}"/>
</div>
<div class="col-xs-4">
<input type="text" class="form-control" id="feature-code" placeholder="code" value="{{this.code}}"/>
<input type="text" class="form-control feature-code" placeholder="code" value="{{this.code}}"/>
</div>
<div class="col-xs-4">
<textarea aria-describedby="basic-addon1" type="text" id="feature-description"
placeholder="description" data-error-msg="invalid feature description" class="form-control" rows="1" cols="30">{{this.description}}</textarea>
<textarea aria-describedby="basic-addon1" type="text"
placeholder="description" data-error-msg="invalid feature description"
class="form-control feature-description" rows="1" cols="30">{{this.description}}</textarea>
</div>
<button type="button" class="wr-btn wr-btn-horizontal remove_feature_button"><i class="fa fa-minus"></i></button>
</div>
@ -115,16 +116,16 @@
<div class="row">
<div class="dontfloat feature-wrapper" name="deviceFeature">
<div class="col-xs-3">
<input type="text" class="form-control" id="feature-name" placeholder="name"/>
<input type="text" class="form-control feature-name" placeholder="name"/>
</div>
<div class="col-xs-4">
<input type="text" class="form-control" id="feature-code" placeholder="code"/>
<input type="text" class="form-control feature-code" placeholder="code"/>
</div>
<div class="col-xs-4">
<textarea aria-describedby="basic-addon1" type="text" id="feature-description"
<textarea aria-describedby="basic-addon1" type="text"
placeholder="description"
data-error-msg="invalid feature description"
class="form-control" rows="1" cols="30"></textarea>
class="form-control feature-description" rows="1" cols="30"></textarea>
</div>
<button type="button" class="wr-btn wr-btn-horizontal add_feature_button"><i class="fa fa-plus"></i></button>
</div>
@ -221,7 +222,7 @@
</div>
<br>
<button id="add-devicetype-btn" class="wr-btn">Update</button>
<button id="edit-devicetype-btn" class="wr-btn">Update</button>
<div id="devicetype-create-success-msg" class="alert hidden" role="alert">
<i class="icon fw fw-success"></i><span></span>
</div>
@ -268,4 +269,4 @@
{{#zone "bottomJs"}}
{{js "js/bottomJs.js"}}
{{/zone}}
{{/zone}}

@ -123,27 +123,28 @@ $(document).ready(function () {
var addFeatureButton = $('.add_feature_button'); //Add button selector
var featureWrapper = $('.feature_field_wrapper'); //Input field wrapper
$(addFeatureButton).click(function(){ //Once add button is clicked
var featureFieldHtml = '<div class="row"><div class="dontfloat feature-wrapper" name ="deviceFeature"> <div class="col-xs-3"> <input type="text"' +
' class="form-control" id="feature-name" placeholder="name"/> </div> <div class="col-xs-4"> ' +
'<input type="text" class="form-control" id="feature-code" placeholder="code"/> </div> ' +
'<div class="col-xs-4"> <textarea aria-describedby="basic-addon1" type="text" ' +
'id="feature-description" placeholder="description"data-error-msg="invalid ' +
'feature description"class="form-control" rows="1" cols="30"></textarea> </div> ' +
'<button type="button" class="wr-btn wr-btn-horizontal wr-btn-secondary remove_feature_button"><i class="fa fa-minus"></i></button> </div></div>'
var featureFieldHtml = '<div class="row"><div class="dontfloat feature-wrapper" name ="deviceFeature"> ' +
'<div class="col-xs-3"> <input type="text"' +
' class="form-control feature-name" placeholder="name"/> </div> <div class="col-xs-4"> ' +
'<input type="text" class="form-control feature-code" placeholder="code"/> </div> ' +
'<div class="col-xs-4"> <textarea aria-describedby="basic-addon1" type="text" ' +
'class="feature-description" placeholder="description"data-error-msg="invalid ' +
'feature description" class="form-control" rows="1" cols="30"></textarea> </div> ' +
'<button type="button" class="wr-btn wr-btn-horizontal wr-btn-secondary remove_feature_button">' +
'<i class="fa fa-minus"></i></button> </div></div>';
$(featureWrapper).append(featureFieldHtml); // Add field html
});
$(featureWrapper).on('click', '.remove_feature_button', function(e){ //Once remove button is clicked
e.preventDefault();
$(this).parent('div').remove(); //Remove field html
op--; //Decrement field counter
});
/**
* Following click function would execute
* when a user clicks on "Add Device type" button.
*/
$("button#add-devicetype-btn").click(function () {
$("button#edit-devicetype-btn").click(function () {
var errorMsgWrapper = "#devicetype-create-error-msg";
var errorMsg = "#devicetype-create-error-msg span";
@ -155,13 +156,19 @@ $(document).ready(function () {
if (!deviceTypeName || deviceTypeName.trim() == "" ) {
$(errorMsg).text("Device Type Name Cannot be empty.");
$(errorMsgWrapper).removeClass("hidden");
$([document.documentElement, document.body]).animate({
scrollTop: $(".page-sub-title").offset().top
}, 500);
return;
}
if (!deviceTypeDescription || deviceTypeDescription.trim() == "" ) {
if (!deviceTypeDescription || deviceTypeDescription.trim() == "") {
$(errorMsg).text("Device Type Description Cannot be empty.");
$(errorMsgWrapper).removeClass("hidden");
return
$([document.documentElement, document.body]).animate({
scrollTop: $(".page-sub-title").offset().top
}, 500);
return;
}
deviceType.name = deviceTypeName.trim();
@ -197,17 +204,29 @@ $(document).ready(function () {
}
var features = [];
var featureCodesValidation = true;
var regexp = /^[a-zA-Z0-9-_]+$/;
$('div[name^="deviceFeature"]').each(function() {
var featureName = $(this).find("#feature-name").val();
var featureCode = $(this).find("#feature-code").val();
if (featureName && featureName.trim() != "" && featureCode && featureCode.trim() != "") {
var feature = {};
feature.name = featureName.trim();
feature.code = featureCode.trim();
feature.description = $("#feature-description").val();
features.push(feature);
}
var featureName = $(this).find(".feature-name").val();
var featureCode = $(this).find(".feature-code").val();
var featureDescription = $(this).find(".feature-description").val();
if (featureName && featureName.trim() != "" && featureCode && featureCode.trim() != "") {
featureCodesValidation = featureCodesValidation && (featureCode.search(regexp) != -1);
var feature = {};
feature.name = featureName.trim();
feature.code = featureCode.trim();
feature.description = featureDescription;
features.push(feature);
}
});
if (!featureCodesValidation) {
$(errorMsg).text("Device Type feature code can only contain alphanumeric, underscore and dash characters.");
$(errorMsgWrapper).removeClass("hidden");
$([document.documentElement, document.body]).animate({
scrollTop: $(".page-sub-title").offset().top
}, 500);
return;
}
deviceType.deviceTypeMetaDefinition.features = features;
var addRoleAPI = apiBasePath + "/admin/device-types/" + deviceType.name;
@ -217,6 +236,7 @@ $(document).ready(function () {
deviceType,
function (data, textStatus, jqXHR) {
if (jqXHR.status == 200) {
$(errorMsgIdentifier).addClass(" hidden");
$("#modalDevice").modal('show');
}
},
@ -234,4 +254,4 @@ $(document).ready(function () {
);
});
});
});

@ -40,4 +40,5 @@
{{#zone "content"}}
{{unit "cdmf.unit.device.operation-mod"}}
{{unit "cdmf.unit.effective-policy.view"}}
{{unit "cdmf.unit.lib.data-table"}}
{{/zone}}

@ -76,25 +76,26 @@ var displayPolicy = function (policyPayloadObj) {
var policyOperationsStylesSrc = context + '/public/cdmf.unit.device.type.' + deviceType +
'.policy-view/css/' + deviceType + '-policy-view.css';
var policyOperationsTemplateCacheKey = deviceType + '-policy-operations';
$.isResourceExists(policyOperationsTemplateSrc, function (status) {
if (policyOperationsTemplateSrc) {
if (policyOperationsScriptSrc) {
var script = document.createElement('script');
script.type = 'text/javascript';
script.src = policyOperationsScriptSrc;
$(".wr-advance-operations").prepend(script);
}
$.template(policyOperationsTemplateCacheKey, policyOperationsTemplateSrc, function (template) {
var content = template();
$("#device-type-policy-operations").html(content).removeClass("hidden");
$(".policy-platform").addClass("hidden");
$.isResourceExists(policyOperationsScriptSrc, function (status) {
var script = document.createElement('script');
script.type = 'text/javascript';
script.src = policyOperationsScriptSrc;
$(".wr-advance-operations").prepend(script);
if (policyOperationsScriptSrc) {
/*
This method should be implemented in the relevant plugin side and should include the logic to
populate the policy profile in the plugin specific UI.
*/
polulateProfileOperations(policyPayloadObj["profile"]["profileFeaturesList"]);
});
}
});
$.isResourceExists(policyOperationsStylesSrc, function (status) {
var style = document.createElement('link');
style.type = 'text/css';
@ -104,7 +105,7 @@ var displayPolicy = function (policyPayloadObj) {
});
$(".wr-advance-operations-init").addClass("hidden");
});
}
};
/**

Loading…
Cancel
Save