From b8f623e04ad5e19350c710bc9840d5ed5e19a460 Mon Sep 17 00:00:00 2001 From: Rasika Perera Date: Mon, 17 Oct 2016 10:51:39 +0530 Subject: [PATCH 1/2] Supporting custom contentTypes for service invoker --- .../jaggeryapps/devicemgt/api/invoker-api.jag | 23 +++++++-- .../oauth/token-protected-service-invokers.js | 51 +++++++++++++++---- 2 files changed, 58 insertions(+), 16 deletions(-) diff --git a/components/device-mgt/org.wso2.carbon.device.mgt.ui/src/main/resources/jaggeryapps/devicemgt/api/invoker-api.jag b/components/device-mgt/org.wso2.carbon.device.mgt.ui/src/main/resources/jaggeryapps/devicemgt/api/invoker-api.jag index 3e410ee2c5..b701ad3f01 100644 --- a/components/device-mgt/org.wso2.carbon.device.mgt.ui/src/main/resources/jaggeryapps/devicemgt/api/invoker-api.jag +++ b/components/device-mgt/org.wso2.carbon.device.mgt.ui/src/main/resources/jaggeryapps/devicemgt/api/invoker-api.jag @@ -27,6 +27,12 @@ var devicemgtProps = require("/app/modules/conf-reader/main.js")["conf"]; var serviceInvokers = require("/app/modules/oauth/token-protected-service-invokers.js")["invokers"]; if (uriMatcher.match("/{context}/api/invoker/execute/")) { + //NOTE: We are only interested in Content-Type headers. Appending all request headers to the back-end call + // will cause unforeseen security issues. + var contentType = request.getHeader(constants.CONTENT_TYPE_IDENTIFIER); + var requestHeaders = []; + requestHeaders.push({"name": constants.CONTENT_TYPE_IDENTIFIER, "value" : contentType}); + var restAPIRequestDetails = request.getContent(); var requestMethod = restAPIRequestDetails["requestMethod"]; @@ -57,7 +63,8 @@ if (uriMatcher.match("/{context}/api/invoker/execute/")) { if (restAPIResponse["responseText"]) { response["content"] = restAPIResponse["responseText"]; } - } + }, + requestHeaders ); break; case constants["HTTP_POST"]: @@ -69,7 +76,8 @@ if (uriMatcher.match("/{context}/api/invoker/execute/")) { if (restAPIResponse["responseText"]) { response["content"] = restAPIResponse["responseText"]; } - } + }, + requestHeaders ); break; case constants["HTTP_PUT"]: @@ -81,7 +89,8 @@ if (uriMatcher.match("/{context}/api/invoker/execute/")) { if (restAPIResponse["responseText"]) { response["content"] = restAPIResponse["responseText"]; } - } + }, + requestHeaders ); break; case constants["HTTP_DELETE"]: @@ -92,13 +101,17 @@ if (uriMatcher.match("/{context}/api/invoker/execute/")) { if (restAPIResponse["responseText"]) { response["content"] = restAPIResponse["responseText"]; } - } + }, + requestHeaders ); break; } } catch (e) { + //Since this is an API we'll log the error message. + log.error(e.message); // JavaScript error message + log.error(e.stack); // Executed JavaScript file stack throw new Error("Exception occurred while trying to access " + - "backend REST API services from Jaggery API invoker layer", e); + "backend REST API services from Jaggery API invoker layer", e); } } %> diff --git a/components/device-mgt/org.wso2.carbon.device.mgt.ui/src/main/resources/jaggeryapps/devicemgt/app/modules/oauth/token-protected-service-invokers.js b/components/device-mgt/org.wso2.carbon.device.mgt.ui/src/main/resources/jaggeryapps/devicemgt/app/modules/oauth/token-protected-service-invokers.js index b79e7c6a07..bb260ae5ea 100644 --- a/components/device-mgt/org.wso2.carbon.device.mgt.ui/src/main/resources/jaggeryapps/devicemgt/app/modules/oauth/token-protected-service-invokers.js +++ b/components/device-mgt/org.wso2.carbon.device.mgt.ui/src/main/resources/jaggeryapps/devicemgt/app/modules/oauth/token-protected-service-invokers.js @@ -73,11 +73,26 @@ var invokers = function () { var xmlHttpRequest = new XMLHttpRequest(); xmlHttpRequest.open(httpMethod, endpoint); + + var contentTypeFound = false; + var acceptTypeFound = false; for (var i in headers) { xmlHttpRequest.setRequestHeader(headers[i].name, headers[i].value); + if(constants["CONTENT_TYPE_IDENTIFIER"] == headers[i].name){ + contentTypeFound = true; + } + if(constants["ACCEPT_IDENTIFIER"] == headers[i].name){ + acceptTypeFound = true; + } + } + + if (!contentTypeFound) { + xmlHttpRequest.setRequestHeader(constants["CONTENT_TYPE_IDENTIFIER"], constants["APPLICATION_JSON"]); + } + + if (!acceptTypeFound) { + xmlHttpRequest.setRequestHeader(constants["ACCEPT_IDENTIFIER"], constants["APPLICATION_JSON"]); } - xmlHttpRequest.setRequestHeader(constants["CONTENT_TYPE_IDENTIFIER"], constants["APPLICATION_JSON"]); - xmlHttpRequest.setRequestHeader(constants["ACCEPT_IDENTIFIER"], constants["APPLICATION_JSON"]); if (devicemgtProps["isOAuthEnabled"]) { var accessToken = privateMethods.getAccessToken(); @@ -284,23 +299,37 @@ var invokers = function () { //noinspection JSUnresolvedVariable var Header = Packages.org.apache.commons.httpclient.Header; + var contentTypeFound = false; + var acceptTypeFound = false; for (var i in headers) { var header = new Header(); header.setName(headers[i].name); header.setValue(headers[i].value); httpMethodObject.addRequestHeader(header); + + if(constants["CONTENT_TYPE_IDENTIFIER"] == headers[i].name){ + contentTypeFound = true; + } + if(constants["ACCEPT_IDENTIFIER"] == headers[i].name){ + acceptTypeFound = true; + } } var header = new Header(); - header.setName(constants["CONTENT_TYPE_IDENTIFIER"]); - header.setValue(constants["APPLICATION_JSON"]); - //noinspection JSUnresolvedFunction - httpMethodObject.addRequestHeader(header); - header = new Header(); - header.setName(constants["ACCEPT_IDENTIFIER"]); - header.setValue(constants["APPLICATION_JSON"]); - //noinspection JSUnresolvedFunction - httpMethodObject.addRequestHeader(header); + if(!contentTypeFound){ + header.setName(constants["CONTENT_TYPE_IDENTIFIER"]); + header.setValue(constants["APPLICATION_JSON"]); + //noinspection JSUnresolvedFunction + httpMethodObject.addRequestHeader(header); + } + + if(!acceptTypeFound) { + header = new Header(); + header.setName(constants["ACCEPT_IDENTIFIER"]); + header.setValue(constants["APPLICATION_JSON"]); + //noinspection JSUnresolvedFunction + httpMethodObject.addRequestHeader(header); + } if (devicemgtProps["isOAuthEnabled"]) { var accessToken = privateMethods.getAccessToken(); From 28cb653b06774716b8188416acde5f7e93716528 Mon Sep 17 00:00:00 2001 From: Shavindri Date: Mon, 17 Oct 2016 14:21:30 +0530 Subject: [PATCH 2/2] Added swagger annotations and refined the messages for certificate management, and created the swagger extensions file. --- .../CertificateManagementAdminService.java | 16 ++--- .../SecurityDefinitionConfigurator.java | 60 +++++++++++++++++++ .../src/main/webapp/WEB-INF/cxf-servlet.xml | 1 + .../service/api/DeviceManagementService.java | 2 +- .../api/NotificationManagementService.java | 6 +- 5 files changed, 74 insertions(+), 11 deletions(-) create mode 100644 components/certificate-mgt/org.wso2.carbon.certificate.mgt.cert.admin.api/src/main/java/org/wso2/carbon/certificate/mgt/cert/jaxrs/api/swagger/extension/SecurityDefinitionConfigurator.java diff --git a/components/certificate-mgt/org.wso2.carbon.certificate.mgt.cert.admin.api/src/main/java/org/wso2/carbon/certificate/mgt/cert/jaxrs/api/CertificateManagementAdminService.java b/components/certificate-mgt/org.wso2.carbon.certificate.mgt.cert.admin.api/src/main/java/org/wso2/carbon/certificate/mgt/cert/jaxrs/api/CertificateManagementAdminService.java index 0ed5d4c44b..b34e83f0e1 100644 --- a/components/certificate-mgt/org.wso2.carbon.certificate.mgt.cert.admin.api/src/main/java/org/wso2/carbon/certificate/mgt/cert/jaxrs/api/CertificateManagementAdminService.java +++ b/components/certificate-mgt/org.wso2.carbon.certificate.mgt.cert.admin.api/src/main/java/org/wso2/carbon/certificate/mgt/cert/jaxrs/api/CertificateManagementAdminService.java @@ -81,9 +81,9 @@ public interface CertificateManagementAdminService { Response addCertificate( @ApiParam( name = "enrollmentCertificates", - value = "The properties to add a new certificate. It includes the following:\n" + - "serial: The unique ID of the certificate.\n" + - "pem: Convert the OpenSSL certificate to the .pem format and base 64 encode the file.\n" + + value = "The properties to add a new certificate. It includes the following: \n" + + "serial: The unique ID of the certificate. \n" + + "pem: Convert the OpenSSL certificate to the .pem format and base 64 encode the file. \n" + "INFO: Upload the .pem file and base 64 encode it using a tool, such as the base64encode.in tool.", required = true) EnrollmentCertificate[] enrollmentCertificates); @@ -166,7 +166,7 @@ public interface CertificateManagementAdminService { value = "Getting Details of Certificates", notes = "Get all the details of the certificates you have used for mutual SSL. In a situation where you wish to " + "view all the certificate details, it is not feasible to show all the details on one " - + "page therefore the details are paginated", + + "page. Therefore, the details are paginated.", tags = "Certificate Management" ) @ApiResponses(value = { @@ -216,7 +216,7 @@ public interface CertificateManagementAdminService { Response getAllCertificates( @ApiParam( name = "offset", - value = "The starting pagination index for the complete list of qualified items", + value = "The starting pagination index for the complete list of qualified items.", required = false, defaultValue = "0") @QueryParam("offset") int offset, @@ -228,7 +228,7 @@ public interface CertificateManagementAdminService { @QueryParam("limit") int limit, @ApiParam( name = "If-Modified-Since", - value = "Checks if the requested variant was modified, since the specified date-time.\n" + + value = "Checks if the requested variant was modified, since the specified date-time. \n" + "Provide the value in the following format: EEE, d MMM yyyy HH:mm:ss Z.\n" + "Example: Mon, 05 Jan 2014 15:10:00 +0200", required = false) @@ -241,7 +241,7 @@ public interface CertificateManagementAdminService { produces = MediaType.APPLICATION_JSON, httpMethod = "DELETE", value = "Deleting an SSL Certificate", - notes = "Delete an SSL certificate that's on the client end", + notes = "Delete an SSL certificate that's on the client end.", tags = "Certificate Management") @ApiResponses(value = { @ApiResponse( @@ -264,7 +264,7 @@ public interface CertificateManagementAdminService { @ApiParam( name = "serialNumber", value = "The serial number of the certificate.\n" + - "NOTE: Make sure that a certificate with the serial number you provide exists in the server. If no, first add a certificate.", + "NOTE: Make sure that a certificate with the serial number you provide exists in the server. If not, first add a certificate.", required = true, defaultValue = "12438035315552875930") @PathParam("serialNumber") String serialNumber); diff --git a/components/certificate-mgt/org.wso2.carbon.certificate.mgt.cert.admin.api/src/main/java/org/wso2/carbon/certificate/mgt/cert/jaxrs/api/swagger/extension/SecurityDefinitionConfigurator.java b/components/certificate-mgt/org.wso2.carbon.certificate.mgt.cert.admin.api/src/main/java/org/wso2/carbon/certificate/mgt/cert/jaxrs/api/swagger/extension/SecurityDefinitionConfigurator.java new file mode 100644 index 0000000000..b880c3d3a8 --- /dev/null +++ b/components/certificate-mgt/org.wso2.carbon.certificate.mgt.cert.admin.api/src/main/java/org/wso2/carbon/certificate/mgt/cert/jaxrs/api/swagger/extension/SecurityDefinitionConfigurator.java @@ -0,0 +1,60 @@ +/* + * Copyright (c) 2016, WSO2 Inc. (http://www.wso2.org) All Rights Reserved. + * + * WSO2 Inc. 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.wso2.carbon.certificate.mgt.cert.jaxrs.api.swagger.extension; + +import io.swagger.annotations.SwaggerDefinition; +import io.swagger.jaxrs.Reader; +import io.swagger.jaxrs.config.ReaderListener; +import io.swagger.models.Swagger; +import io.swagger.models.auth.OAuth2Definition; +import io.swagger.models.auth.SecuritySchemeDefinition; + +import java.util.HashMap; +import java.util.Map; + +@SwaggerDefinition( + basePath = "/api/certificate-mgt/v1.0", + host = "localhost:9443" +) +public class SecurityDefinitionConfigurator implements ReaderListener { + + public static final String TOKEN_AUTH_SCHEME = "swagger_auth"; + + @Override + public void beforeScan(Reader reader, Swagger swagger) { + + } + + @Override + public void afterScan(Reader reader, Swagger swagger) { + OAuth2Definition tokenScheme = new OAuth2Definition(); + tokenScheme.setType("oauth2"); + tokenScheme.setFlow("application"); + tokenScheme.setTokenUrl("https://" + swagger.getHost() + "/oauth2/token"); + tokenScheme.setAuthorizationUrl("https://" + swagger.getHost() + "/oauth2/authorize"); + tokenScheme.addScope("write:everything", "Full access"); + + Map schemes = new HashMap<>(); + schemes.put(TOKEN_AUTH_SCHEME, tokenScheme); + + swagger.setSecurityDefinitions(schemes); + } + +} + diff --git a/components/certificate-mgt/org.wso2.carbon.certificate.mgt.cert.admin.api/src/main/webapp/WEB-INF/cxf-servlet.xml b/components/certificate-mgt/org.wso2.carbon.certificate.mgt.cert.admin.api/src/main/webapp/WEB-INF/cxf-servlet.xml index 68a07fcb86..11511e467d 100644 --- a/components/certificate-mgt/org.wso2.carbon.certificate.mgt.cert.admin.api/src/main/webapp/WEB-INF/cxf-servlet.xml +++ b/components/certificate-mgt/org.wso2.carbon.certificate.mgt.cert.admin.api/src/main/webapp/WEB-INF/cxf-servlet.xml @@ -29,6 +29,7 @@ + diff --git a/components/device-mgt/org.wso2.carbon.device.mgt.api/src/main/java/org/wso2/carbon/device/mgt/jaxrs/service/api/DeviceManagementService.java b/components/device-mgt/org.wso2.carbon.device.mgt.api/src/main/java/org/wso2/carbon/device/mgt/jaxrs/service/api/DeviceManagementService.java index de032b83c7..3838155c1e 100644 --- a/components/device-mgt/org.wso2.carbon.device.mgt.api/src/main/java/org/wso2/carbon/device/mgt/jaxrs/service/api/DeviceManagementService.java +++ b/components/device-mgt/org.wso2.carbon.device.mgt.api/src/main/java/org/wso2/carbon/device/mgt/jaxrs/service/api/DeviceManagementService.java @@ -655,7 +655,7 @@ public interface DeviceManagementService { produces = MediaType.APPLICATION_JSON, httpMethod = "GET", value = "Get the details of the policy that is enforced on a device.", - notes = "A policy is enforced on all the devices that registers with WSO2 EMM." + + notes = "A policy is enforced on all the devices that register with WSO2 EMM." + "WSO2 EMM filters the policies based on the device platform (device type)," + "the device ownership type, the user role or name and finally, the policy that matches these filters will be enforced on the device.", tags = "Device Management") diff --git a/components/device-mgt/org.wso2.carbon.device.mgt.api/src/main/java/org/wso2/carbon/device/mgt/jaxrs/service/api/NotificationManagementService.java b/components/device-mgt/org.wso2.carbon.device.mgt.api/src/main/java/org/wso2/carbon/device/mgt/jaxrs/service/api/NotificationManagementService.java index b7e15ee45e..f1a230e758 100644 --- a/components/device-mgt/org.wso2.carbon.device.mgt.api/src/main/java/org/wso2/carbon/device/mgt/jaxrs/service/api/NotificationManagementService.java +++ b/components/device-mgt/org.wso2.carbon.device.mgt.api/src/main/java/org/wso2/carbon/device/mgt/jaxrs/service/api/NotificationManagementService.java @@ -112,13 +112,15 @@ public interface NotificationManagementService { @ApiParam( name = "offset", value = "The starting pagination index for the complete list of qualified items.", - required = false) + required = false, + defaultValue = "0") @QueryParam("offset") int offset, @ApiParam( name = "limit", value = "Provide how many notification details you require from the starting pagination index/offset.", - required = false) + required = false, + defaultValue = "5") @QueryParam("limit") int limit);