implementing windows 10 enrollment

revert-dabc3590
Hasunie 8 years ago
parent ad812f2328
commit 0456502bbe

@ -31,6 +31,8 @@ public final class PluginConstants {
"org.wso2.carbon.device.mgt.mobile.windows.api.services.wstep.CertificateEnrollmentService";
public static final String CERTIFICATE_ENROLLMENT_POLICY_SERVICE_ENDPOINT =
"org.wso2.carbon.device.mgt.mobile.windows.api.services.xcep.CertificateEnrollmentPolicyService";
public static final String ENROLLMENT_SERVICE_ENDPOINT =
"org.wso2.carbon.device.mgt.mobile.windows.api.services.enrollment.EnrollmentService";
//Services' target namespaces
public static final String DISCOVERY_SERVICE_TARGET_NAMESPACE =
@ -81,10 +83,8 @@ public final class PluginConstants {
"/ENROLLMENTSERVER/PolicyEnrollmentWebservice.svc";
public static final String CERTIFICATE_ENROLLMENT_SERVICE_URL =
"/ENROLLMENTSERVER/DeviceEnrollmentWebservice.svc";
public static final String ONPREMISE_CERTIFICATE_ENROLLMENT_POLICY =
"/ENROLLMENTSERVER/ONPREMISE/PolicyEnrollmentWebservice.svc";
public static final String ONPREMISE_CERTIFICATE_ENROLLMENT_SERVICE_URL =
"/ENROLLMENTSERVER/ONPREMISE/DeviceEnrollmentWebservice.svc";
public static final String ENROLLMENT_SERVICE_URL =
"/ENROLLMENTSERVER/Win10DeviceEnrollmentWebservice.svc";
public static final String WAB_URL = "/windows-web-agent/enrollments/windows/login-agent";
}
@ -153,6 +153,8 @@ public final class PluginConstants {
public static final int DOMAIN_POSITION = 7;
public static final String ENROLL_SUBDOMAIN = "https://EnterpriseEnrollment.";
public static final String SYNCML_PROVISIONING_SERVICE_URL = "/Syncml/initialquery";
public static final String ENROLLMENT_DISPOSITION_MESSAGE = "http://schemas.microsoft.com/windows/pki/" +
"2009/01/enrollment";
}
/**
@ -189,7 +191,7 @@ public final class PluginConstants {
public static final int MODEL_POSITION = 5;
public static final int MAC_ADDRESS_POSITION = 7;
public static final int RESOLUTION_POSITION = 8;
public static final int DEVICE_NAME_POSITION = 9;
public static final int DEVICE_NAME_POSITION = 10;
public static final String SYNCML_DATA_ONE = "1";
public static final String SYNCML_DATA_ZERO = "0";
public static final String OS_VERSION = "OS_VERSION";
@ -289,7 +291,6 @@ public final class PluginConstants {
public static final String DEFAULT_AUTH_POLICY = "Federated";
}
/**
* Policy Configuration related constants.
*/
@ -311,4 +312,32 @@ public final class PluginConstants {
public static final String MAX_CONNECTION_PER_HOST = "MaxConnectionsPerHost";
public static final String MAX_TOTAL_CONNECTIONS = "MaxTotalConnections";
}
/**
* Windows version related constants.
*/
public final class WindowsVersionProperties {
private WindowsVersionProperties() {
throw new AssertionError();
}
public static final String REQUESTED_WIN10_VERSION = "3.0";
public static final String REQUESTED_WIN81_VERSION = "2.0";
}
/**
* Windows enrollment property constants.
*/
public final class WindowsEnrollmentProperties {
private WindowsEnrollmentProperties() {
throw new AssertionError();
}
public static final int WIN_DEVICE_ID = 12;
public static final int WIN_DEVICE_NAME = 2;
public static final int WIN_DEVICE_VERSION = 15;
public static final int WIN_DEVICE_IMEI = 3;
}
}

@ -18,14 +18,12 @@
package org.wso2.carbon.device.mgt.mobile.windows.api.services.discovery.beans;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlType;
import javax.xml.bind.annotation.*;
import java.io.Serializable;
import java.util.List;
@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "DiscoveryRequest")
@XmlType(name = "DiscoveryRequest", namespace = "http://schemas.microsoft.com/windows/management/2012/01/enrollment")
@SuppressWarnings("unused")
public class DiscoveryRequest implements Serializable {
@ -38,18 +36,28 @@ public class DiscoveryRequest implements Serializable {
@XmlElement(name = "DeviceType")
private String deviceType;
@XmlElement(name = "OSEdition")
private String osEdition;
@XmlElement(name = "ApplicationVersion")
private String applicationVersion;
@XmlElementWrapper(name = "AuthPolicies")
@XmlElement(name = "AuthPolicy", required = true)
private List<String> authenticationPolicies;
public String getEmailId() {
return emailId;
}
public String getVersion() {
return version;
}
public void setEmailId(String emailId) {
this.emailId = emailId;
}
public String getVersion() {
return version;
}
public void setVersion(String version) {
this.version = version;
}
@ -61,4 +69,21 @@ public class DiscoveryRequest implements Serializable {
public void setDeviceType(String deviceType) {
this.deviceType = deviceType;
}
public List<String> getAuthenticationPolicies() {
return authenticationPolicies;
}
public void setAuthenticationPolicies(List<String> authenticationPolicies) {
this.authenticationPolicies = authenticationPolicies;
}
public String getOsEdition() {
return osEdition;
}
public void setOsEdition(String osEdition) {
this.osEdition = osEdition;
}
}

@ -41,6 +41,9 @@ public class DiscoveryResponse implements Serializable {
@XmlElement(name = "AuthenticationServiceUrl")
private String authenticationServiceUrl;
@XmlElement(name = "EnrollmentVersion")
private String enrollmentVersion;
public void setAuthenticationServiceUrl(String authenticationServiceUrl) {
this.authenticationServiceUrl = authenticationServiceUrl;
}
@ -73,4 +76,12 @@ public class DiscoveryResponse implements Serializable {
this.enrollmentServiceUrl = enrollmentServiceUrl;
}
public String getEnrollmentVersion() {
return enrollmentVersion;
}
public void setEnrollmentVersion(String enrollmentVersion) {
this.enrollmentVersion = enrollmentVersion;
}
}

@ -68,9 +68,23 @@ public class DiscoveryServiceImpl implements DiscoveryService {
String emailId = discoveryRequest.getEmailId();
String[] userDomains = emailId.split(DELIMITER);
String domain = userDomains[DOMAIN_SEGMENT];
DiscoveryResponse discoveryResponse;
if (PluginConstants.WindowsVersionProperties.REQUESTED_WIN10_VERSION.equals(discoveryRequest.getVersion()) &&
FEDERATED.equals(getAuthPolicy())) {
discoveryResponse = new DiscoveryResponse();
DiscoveryResponse discoveryResponse = new DiscoveryResponse();
if (FEDERATED.equals(getAuthPolicy())) {
discoveryResponse.setAuthPolicy(FEDERATED);
discoveryResponse.setEnrollmentVersion(PluginConstants.WindowsVersionProperties.REQUESTED_WIN10_VERSION);
discoveryResponse.setEnrollmentPolicyServiceUrl(PluginConstants.Discovery.DEVICE_ENROLLMENT_SUBDOMAIN +
domain + PluginConstants.Discovery.
CERTIFICATE_ENROLLMENT_POLICY_SERVICE_URL);
discoveryResponse.setEnrollmentServiceUrl(PluginConstants.Discovery.DEVICE_ENROLLMENT_SUBDOMAIN +
domain + PluginConstants.Discovery.
ENROLLMENT_SERVICE_URL);
discoveryResponse.setAuthenticationServiceUrl(PluginConstants.Discovery.DEVICE_ENROLLMENT_SUBDOMAIN +
domain + PluginConstants.Discovery.WAB_URL);
} else {
discoveryResponse = new DiscoveryResponse();
discoveryResponse.setAuthPolicy(FEDERATED);
discoveryResponse.setEnrollmentPolicyServiceUrl(PluginConstants.Discovery.DEVICE_ENROLLMENT_SUBDOMAIN +
domain + PluginConstants.Discovery.

@ -0,0 +1,43 @@
package org.wso2.carbon.device.mgt.mobile.windows.api.services.enrollment;
import org.wso2.carbon.device.mgt.mobile.windows.api.common.PluginConstants;
import org.wso2.carbon.device.mgt.mobile.windows.api.common.exceptions.WAPProvisioningException;
import org.wso2.carbon.device.mgt.mobile.windows.api.common.exceptions.WindowsDeviceEnrolmentException;
import org.wso2.carbon.device.mgt.mobile.windows.api.services.enrollment.beans.AdditionalContext;
import org.wso2.carbon.device.mgt.mobile.windows.api.services.enrollment.beans.RequestSecurityTokenResponse;
import javax.jws.WebMethod;
import javax.jws.WebParam;
import javax.jws.WebService;
import javax.xml.ws.BindingType;
import javax.xml.ws.RequestWrapper;
import javax.xml.ws.ResponseWrapper;
import javax.xml.ws.soap.SOAPBinding;
import java.io.UnsupportedEncodingException;
@WebService(targetNamespace = PluginConstants.DEVICE_ENROLLMENT_SERVICE_TARGET_NAMESPACE, name = "enrollment")
@BindingType(value = SOAPBinding.SOAP12HTTP_BINDING)
public interface EnrollmentService {
@RequestWrapper(localName = "RequestSecurityToken", targetNamespace = PluginConstants
.WS_TRUST_TARGET_NAMESPACE)
@WebMethod(operationName = "RequestSecurityToken")
@ResponseWrapper(localName = "RequestSecurityTokenResponseCollection", targetNamespace =
PluginConstants.WS_TRUST_TARGET_NAMESPACE)
void requestSecurityToken(
@WebParam(name = "TokenType", targetNamespace = PluginConstants.WS_TRUST_TARGET_NAMESPACE)
String tokenType,
@WebParam(name = "RequestType", targetNamespace = PluginConstants.WS_TRUST_TARGET_NAMESPACE)
String requestType,
@WebParam(name = "BinarySecurityToken", targetNamespace = PluginConstants
.WS_SECURITY_TARGET_NAMESPACE)
String binarySecurityToken,
@WebParam(name = "AdditionalContext", targetNamespace = PluginConstants
.SOAP_AUTHORIZATION_TARGET_NAMESPACE)
AdditionalContext additionalContext,
@WebParam(mode = WebParam.Mode.OUT, name = "RequestSecurityTokenResponse",
targetNamespace = PluginConstants.WS_TRUST_TARGET_NAMESPACE)
javax.xml.ws.Holder<RequestSecurityTokenResponse> response) throws
WindowsDeviceEnrolmentException, UnsupportedEncodingException,
WAPProvisioningException;
}

@ -0,0 +1,48 @@
/*
* 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.device.mgt.mobile.windows.api.services.enrollment.beans;
import org.wso2.carbon.device.mgt.mobile.windows.api.common.PluginConstants;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlType;
import java.util.ArrayList;
import java.util.List;
@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "OIDCollection", namespace = PluginConstants.SOAP_AUTHORIZATION_TARGET_NAMESPACE,
propOrder = {"contextitem"})
@SuppressWarnings("unused")
public class AdditionalContext {
@XmlElement(name = "ContextItem", required = true,
namespace = PluginConstants.SOAP_AUTHORIZATION_TARGET_NAMESPACE)
protected List<ContextItem> contextitem;
public List<ContextItem> getcontextitem() {
if (contextitem == null) {
contextitem = new ArrayList<ContextItem>();
}
return this.contextitem;
}
}

@ -0,0 +1,63 @@
/*
* 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.device.mgt.mobile.windows.api.services.enrollment.beans;
import org.wso2.carbon.device.mgt.mobile.windows.api.common.PluginConstants;
import javax.xml.bind.annotation.*;
@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "BinarySecurityToken", namespace = PluginConstants.WS_SECURITY_TARGET_NAMESPACE,
propOrder = {"ValueType", "EncodingType"})
@SuppressWarnings("unused")
public class BinarySecurityToken {
@XmlAttribute(name = "ValueType")
protected String ValueType;
@XmlAttribute(name = "EncodingType")
protected String EncodingType;
@XmlValue
protected String Token;
public void setValueType(String valuetype) {
this.ValueType = valuetype;
}
public String getValueType() {
return this.ValueType;
}
public void setEncodingType(String encodingtype) {
this.EncodingType = encodingtype;
}
public String getEncodingType() {
return this.EncodingType;
}
public void setToken(String token) {
this.Token = token;
}
public String getToken() {
return this.Token;
}
}

@ -0,0 +1,54 @@
/*
* 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.device.mgt.mobile.windows.api.services.enrollment.beans;
import org.wso2.carbon.device.mgt.mobile.windows.api.common.PluginConstants;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlType;
@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "ContextItem", namespace = PluginConstants.SOAP_AUTHORIZATION_TARGET_NAMESPACE,
propOrder = {"Name" , "Value"})
public class ContextItem {
@XmlElement(required = true, namespace = PluginConstants.SOAP_AUTHORIZATION_TARGET_NAMESPACE)
protected String Name;
@XmlElement(required = true, namespace = PluginConstants.SOAP_AUTHORIZATION_TARGET_NAMESPACE)
protected String Value;
public String getValue() {
return Value;
}
public void setValue(String value) {
Value = value;
}
public String getName() {
return Name;
}
public void setName(String name) {
Name = name;
}
}

@ -0,0 +1,42 @@
/*
* 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.device.mgt.mobile.windows.api.services.enrollment.beans;
import org.wso2.carbon.device.mgt.mobile.windows.api.common.PluginConstants;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlType;
@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "RequestedSecurityToken", namespace = PluginConstants.WS_TRUST_TARGET_NAMESPACE,
propOrder = {"binarySecurityToken"})
@SuppressWarnings("unused")
public class RequestSecurityToken {
@XmlElement(name = "BinarySecurityToken", required = true,
namespace = PluginConstants.WS_SECURITY_TARGET_NAMESPACE)
protected BinarySecurityToken binarySecurityToken;
public void setBinarySecurityToken(BinarySecurityToken binarysecuritytoken) {
this.binarySecurityToken = binarysecuritytoken;
}
}

@ -0,0 +1,82 @@
/*
* 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.device.mgt.mobile.windows.api.services.enrollment.beans;
import org.wso2.carbon.device.mgt.mobile.windows.api.common.PluginConstants;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlType;
import java.io.Serializable;
@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "RequestSecurityTokenResponse", namespace = PluginConstants.WS_TRUST_TARGET_NAMESPACE,
propOrder = {"TokenType", "DispositionMessage", "RequestedSecurityToken", "RequestID"})
@SuppressWarnings("unused")
public class RequestSecurityTokenResponse implements Serializable {
@XmlElement(name = "TokenType", namespace = PluginConstants.WS_TRUST_TARGET_NAMESPACE)
private String TokenType;
// Windows 10 property
@XmlElement(name = "DispositionMessage", namespace = PluginConstants.ENROLLMENT_POLICY_TARGET_NAMESPACE)
private String DispositionMessage;
@XmlElement(name = "RequestedSecurityToken", required = true,
namespace = PluginConstants.WS_TRUST_TARGET_NAMESPACE)
private org.wso2.carbon.device.mgt.mobile.windows.api.services.enrollment.beans.RequestedSecurityToken RequestedSecurityToken;
@XmlElement(name = "RequestID", namespace = PluginConstants.ENROLLMENT_POLICY_TARGET_NAMESPACE)
private int RequestID;
public String getTokenType() {
return TokenType;
}
public void setTokenType(String tokenType) {
TokenType = tokenType;
}
public org.wso2.carbon.device.mgt.mobile.windows.api.services.enrollment.beans.RequestedSecurityToken getRequestedSecurityToken() {
return RequestedSecurityToken;
}
public void setRequestedSecurityToken(org.wso2.carbon.device.mgt.mobile.windows.api.services.enrollment.beans.RequestedSecurityToken
requestedSecurityToken) {
RequestedSecurityToken = requestedSecurityToken;
}
public int getRequestID() {
return RequestID;
}
public void setRequestID(int requestID) {
RequestID = requestID;
}
public String getDispositionMessage() {
return DispositionMessage;
}
public void setDispositionMessage(String dispositionMessage) {
DispositionMessage = dispositionMessage;
}
}

@ -0,0 +1,42 @@
/*
* 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.device.mgt.mobile.windows.api.services.enrollment.beans;
import org.wso2.carbon.device.mgt.mobile.windows.api.common.PluginConstants;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlType;
@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "RequestedSecurityToken", namespace = PluginConstants.WS_TRUST_TARGET_NAMESPACE,
propOrder = {"binarySecurityToken"})
public class RequestedSecurityToken {
@XmlElement(name = "BinarySecurityToken", required = true,
namespace = PluginConstants.WS_SECURITY_TARGET_NAMESPACE)
protected BinarySecurityToken binarySecurityToken;
public void setBinarySecurityToken(BinarySecurityToken binarysecuritytoken) {
this.binarySecurityToken = binarysecuritytoken;
}
}

@ -0,0 +1,27 @@
/*
* 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.
*/
@XmlSchema(namespace = "http://www.w3.org/2003/05/soap-envelope",
xmlns = {
@XmlNs(prefix = "", namespaceURI = "http://www.w3.org/2003/05/soap-envelope")
}, elementFormDefault = javax.xml.bind.annotation.XmlNsForm.QUALIFIED)
package org.wso2.carbon.device.mgt.mobile.windows.api.services.enrollment.beans;
import javax.xml.bind.annotation.XmlNs;
import javax.xml.bind.annotation.XmlSchema;

@ -0,0 +1,394 @@
package org.wso2.carbon.device.mgt.mobile.windows.api.services.enrollment.impl;
import org.apache.commons.codec.binary.Base64;
import org.apache.commons.codec.digest.DigestUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.cxf.headers.Header;
import org.apache.cxf.helpers.CastUtils;
import org.apache.cxf.jaxws.context.WrappedMessageContext;
import org.apache.cxf.message.Message;
import org.w3c.dom.*;
import org.wso2.carbon.certificate.mgt.core.exception.KeystoreException;
import org.wso2.carbon.certificate.mgt.core.service.CertificateManagementServiceImpl;
import org.wso2.carbon.context.PrivilegedCarbonContext;
import org.wso2.carbon.device.mgt.common.DeviceManagementConstants;
import org.wso2.carbon.device.mgt.common.DeviceManagementException;
import org.wso2.carbon.device.mgt.common.EnrolmentInfo;
import org.wso2.carbon.device.mgt.common.configuration.mgt.ConfigurationEntry;
import org.wso2.carbon.device.mgt.mobile.windows.api.common.PluginConstants;
import org.wso2.carbon.device.mgt.mobile.windows.api.common.beans.CacheEntry;
import org.wso2.carbon.device.mgt.mobile.windows.api.common.beans.Device;
import org.wso2.carbon.device.mgt.mobile.windows.api.common.exceptions.CertificateGenerationException;
import org.wso2.carbon.device.mgt.mobile.windows.api.common.exceptions.SyncmlMessageFormatException;
import org.wso2.carbon.device.mgt.mobile.windows.api.common.exceptions.WAPProvisioningException;
import org.wso2.carbon.device.mgt.mobile.windows.api.common.exceptions.WindowsDeviceEnrolmentException;
import org.wso2.carbon.device.mgt.mobile.windows.api.common.util.DeviceUtil;
import org.wso2.carbon.device.mgt.mobile.windows.api.common.util.WindowsAPIUtils;
import org.wso2.carbon.device.mgt.mobile.windows.api.operations.util.SyncmlCredentialUtil;
import org.wso2.carbon.device.mgt.mobile.windows.api.services.enrollment.EnrollmentService;
import org.wso2.carbon.device.mgt.mobile.windows.api.services.enrollment.beans.*;
import org.wso2.carbon.device.mgt.mobile.windows.api.services.syncml.beans.WindowsDevice;
import org.xml.sax.SAXException;
import javax.annotation.Resource;
import javax.jws.WebService;
import javax.servlet.ServletContext;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
import javax.xml.ws.BindingType;
import javax.xml.ws.Holder;
import javax.xml.ws.WebServiceContext;
import javax.xml.ws.handler.MessageContext;
import javax.xml.ws.soap.Addressing;
import javax.xml.ws.soap.SOAPBinding;
import java.io.File;
import java.io.IOException;
import java.io.StringWriter;
import java.io.UnsupportedEncodingException;
import java.security.cert.CertificateEncodingException;
import java.security.cert.X509Certificate;
import java.util.ArrayList;
import java.util.List;
/**
* Implementation class of CertificateEnrollmentService interface. This class implements MS-WSTEP
* protocol.
*/
@WebService(endpointInterface = PluginConstants.ENROLLMENT_SERVICE_ENDPOINT,
targetNamespace = PluginConstants.DEVICE_ENROLLMENT_SERVICE_TARGET_NAMESPACE)
@Addressing(enabled = true, required = true)
@BindingType(value = SOAPBinding.SOAP12HTTP_BINDING)
public class EnrollmentServiceImpl implements EnrollmentService {
private static Log log = LogFactory.getLog(EnrollmentServiceImpl.class);
private X509Certificate rootCACertificate;
private String pollingFrequency;
private String provisioningURL;
private String domain;
@Resource
private WebServiceContext context;
@Override
public void requestSecurityToken(String tokenType, String requestType, String binarySecurityToken,
AdditionalContext additionalContext,
Holder<RequestSecurityTokenResponse> response)
throws WindowsDeviceEnrolmentException, UnsupportedEncodingException, WAPProvisioningException {
String headerBinarySecurityToken = null;
String headerTo = null;
String encodedWap;
List<Header> headers = getHeaders();
WindowsDevice windowsDevice = new WindowsDevice();
for (Header headerElement : headers != null ? headers : null) {
String nodeName = headerElement.getName().getLocalPart();
if (PluginConstants.SECURITY.equals(nodeName)) {
Element element = (Element) headerElement.getObject();
headerBinarySecurityToken = element.getFirstChild().getNextSibling().getFirstChild().getTextContent();
}
if (PluginConstants.TO.equals(nodeName)) {
Element toElement = (Element) headerElement.getObject();
headerTo = toElement.getFirstChild().getTextContent();
}
}
windowsDevice.setDeviceType(DeviceManagementConstants.MobileDeviceTypes.
MOBILE_DEVICE_TYPE_WINDOWS);
windowsDevice.setUser(getRequestedUser(headerBinarySecurityToken));
List<ContextItem> contextItems = additionalContext.getcontextitem();
for (int x= 0; x< contextItems.size(); x++) {
switch (x) {
case PluginConstants.WindowsEnrollmentProperties.WIN_DEVICE_NAME:
windowsDevice.setDeviceName(contextItems.get(x).getValue());
case PluginConstants.WindowsEnrollmentProperties.WIN_DEVICE_IMEI:
windowsDevice.setImei(contextItems.get(x).getValue());
case PluginConstants.WindowsEnrollmentProperties.WIN_DEVICE_ID:
windowsDevice.setDeviceId(contextItems.get(x).getValue());
case PluginConstants.WindowsEnrollmentProperties.WIN_DEVICE_VERSION:
windowsDevice.setOsVersion(contextItems.get(x).getValue());
}
}
/////////
org.wso2.carbon.device.mgt.common.Device device = generateDevice(windowsDevice);
try {
WindowsAPIUtils.getDeviceManagementService().enrollDevice(device);
} catch (DeviceManagementException e) {
e.printStackTrace();
}
/////////
String[] splitEmail = headerTo.split("(/ENROLLMENTSERVER)");
String email = splitEmail[PluginConstants.CertificateEnrolment.EMAIL_SEGMENT];
String[] splitDomain = email.split("(EnterpriseEnrollment.)");
domain = splitDomain[PluginConstants.CertificateEnrolment.DOMAIN_SEGMENT];
provisioningURL = PluginConstants.CertificateEnrolment.ENROLL_SUBDOMAIN + domain +
PluginConstants.CertificateEnrolment.SYNCML_PROVISIONING_SERVICE_URL;
List<ConfigurationEntry> tenantConfigurations;
try {
if ((tenantConfigurations = WindowsAPIUtils.getTenantConfigurationData()) != null) {
for (ConfigurationEntry configurationEntry : tenantConfigurations) {
if ((PluginConstants.TenantConfigProperties.NOTIFIER_FREQUENCY.equals(
configurationEntry.getName()))) {
pollingFrequency = configurationEntry.getValue().toString();
} else {
pollingFrequency = PluginConstants.TenantConfigProperties.DEFAULT_FREQUENCY;
}
}
} else {
pollingFrequency = PluginConstants.TenantConfigProperties.DEFAULT_FREQUENCY;
String msg = "Tenant configurations are not initialized yet.";
log.error(msg);
}
ServletContext ctx = (ServletContext) context.getMessageContext().
get(MessageContext.SERVLET_CONTEXT);
File wapProvisioningFile = (File) ctx.getAttribute(PluginConstants.CONTEXT_WAP_PROVISIONING_FILE);
if (log.isDebugEnabled()) {
log.debug("Received CSR from Device:" + binarySecurityToken);
}
String wapProvisioningFilePath = wapProvisioningFile.getPath();
RequestSecurityTokenResponse requestSecurityTokenResponse = new RequestSecurityTokenResponse();
requestSecurityTokenResponse.setTokenType(PluginConstants.CertificateEnrolment.TOKEN_TYPE);
encodedWap = prepareWapProvisioningXML(binarySecurityToken, wapProvisioningFilePath,
headerBinarySecurityToken);
RequestedSecurityToken requestedSecurityToken = new RequestedSecurityToken();
BinarySecurityToken binarySecToken = new BinarySecurityToken();
binarySecToken.setValueType(PluginConstants.CertificateEnrolment.VALUE_TYPE);
binarySecToken.setEncodingType(PluginConstants.CertificateEnrolment.ENCODING_TYPE);
binarySecToken.setToken(encodedWap);
requestedSecurityToken.setBinarySecurityToken(binarySecToken);
requestSecurityTokenResponse.setRequestedSecurityToken(requestedSecurityToken);
requestSecurityTokenResponse.setRequestID(PluginConstants.CertificateEnrolment.REQUEST_ID);
response.value = requestSecurityTokenResponse;
} catch (CertificateGenerationException e) {
String msg = "Problem occurred while generating certificate.";
log.error(msg, e);
throw new WindowsDeviceEnrolmentException(msg, e);
} catch (WAPProvisioningException e) {
String msg = "Problem occurred while generating wap-provisioning file.";
log.error(msg, e);
throw new WindowsDeviceEnrolmentException(msg, e);
} catch (DeviceManagementException e) {
String msg = "Error occurred while getting tenant configurations.";
log.error(msg);
throw new WindowsDeviceEnrolmentException(msg, e);
} finally {
PrivilegedCarbonContext.endTenantFlow();
}
}
/**
* Method used to Convert the Document object into a String.
*
* @param document - Wap provisioning XML document
* @return - String representation of wap provisioning XML document
* @throws TransformerException
*/
private String convertDocumentToString(Document document) throws TransformerException {
DOMSource DOMSource = new DOMSource(document);
StringWriter stringWriter = new StringWriter();
StreamResult streamResult = new StreamResult(stringWriter);
TransformerFactory transformerFactory = TransformerFactory.newInstance();
Transformer transformer = transformerFactory.newTransformer();
transformer.transform(DOMSource, streamResult);
return stringWriter.toString();
}
/**
* This method prepares the wap-provisioning file by including relevant certificates etc.
*
* @param binarySecurityToken - CSR from device
* @param wapProvisioningFilePath - File path of wap-provisioning file
* @return - base64 encoded final wap-provisioning file as a String
* @throws CertificateGenerationException
* @throws org.wso2.carbon.device.mgt.mobile.windows.api.common.exceptions.WAPProvisioningException
*/
private String prepareWapProvisioningXML(String binarySecurityToken, String wapProvisioningFilePath,
String headerBst) throws CertificateGenerationException,
WAPProvisioningException,
WindowsDeviceEnrolmentException {
String rootCertEncodedString;
String signedCertEncodedString;
X509Certificate signedCertificate;
String provisioningXmlString;
CertificateManagementServiceImpl certMgtServiceImpl = CertificateManagementServiceImpl.getInstance();
Base64 base64Encoder = new Base64();
try {
rootCACertificate = (X509Certificate) certMgtServiceImpl.getCACertificate();
rootCertEncodedString = base64Encoder.encodeAsString(rootCACertificate.getEncoded());
signedCertificate = certMgtServiceImpl.getSignedCertificateFromCSR(binarySecurityToken);
signedCertEncodedString = base64Encoder.encodeAsString(signedCertificate.getEncoded());
DocumentBuilderFactory domFactory = DocumentBuilderFactory.newInstance();
DocumentBuilder builder;
builder = domFactory.newDocumentBuilder();
Document document = builder.parse(wapProvisioningFilePath);
NodeList wapParm = document.getElementsByTagName(PluginConstants.CertificateEnrolment.PARM);
Node caCertificatePosition = wapParm.item(PluginConstants.CertificateEnrolment.CA_CERTIFICATE_POSITION);
//Adding SHA1 CA certificate finger print to wap-provisioning xml.
caCertificatePosition.getParentNode().getAttributes().getNamedItem(PluginConstants.
CertificateEnrolment.TYPE).setTextContent(String.valueOf(
DigestUtils.sha1Hex(rootCACertificate.getEncoded())).toUpperCase());
//Adding encoded CA certificate to wap-provisioning file after removing new line
// characters.
NamedNodeMap rootCertAttributes = caCertificatePosition.getAttributes();
Node rootCertNode =
rootCertAttributes.getNamedItem(PluginConstants.CertificateEnrolment.VALUE);
rootCertEncodedString = rootCertEncodedString.replaceAll("\n", "");
rootCertNode.setTextContent(rootCertEncodedString);
if (log.isDebugEnabled()) {
log.debug("Root certificate: " + rootCertEncodedString);
}
Node signedCertificatePosition = wapParm.item(PluginConstants.CertificateEnrolment.
SIGNED_CERTIFICATE_POSITION);
//Adding SHA1 signed certificate finger print to wap-provisioning xml.
signedCertificatePosition.getParentNode().getAttributes().getNamedItem(PluginConstants.
CertificateEnrolment.TYPE).setTextContent(String.valueOf(
DigestUtils.sha1Hex(signedCertificate.getEncoded())).toUpperCase());
//Adding encoded signed certificate to wap-provisioning file after removing new line
// characters.
NamedNodeMap clientCertAttributes = signedCertificatePosition.getAttributes();
Node clientEncodedNode =
clientCertAttributes.getNamedItem(PluginConstants.CertificateEnrolment.VALUE);
signedCertEncodedString = signedCertEncodedString.replaceAll("\n", "");
clientEncodedNode.setTextContent(signedCertEncodedString);
if (log.isDebugEnabled()) {
log.debug("Signed certificate: " + signedCertEncodedString);
}
//Adding domainName to wap-provisioning xml.
Node domainPosition = wapParm.item(PluginConstants.CertificateEnrolment.DOMAIN_POSITION);
NamedNodeMap domainAttribute = domainPosition.getAttributes();
Node domainNode = domainAttribute.getNamedItem(PluginConstants.CertificateEnrolment.VALUE);
domainNode.setTextContent(domain);
//Adding Next provisioning service URL to wap-provisioning xml.
Node syncmlServicePosition = wapParm.item(PluginConstants.CertificateEnrolment.
SYNCML_PROVISIONING_ADDR_POSITION);
NamedNodeMap syncmlServiceAttribute = syncmlServicePosition.getAttributes();
Node syncmlServiceNode = syncmlServiceAttribute.getNamedItem(PluginConstants.CertificateEnrolment.VALUE);
syncmlServiceNode.setTextContent(provisioningURL);
// Adding user name auth token to wap-provisioning xml.
Node userNameAuthPosition = wapParm.item(PluginConstants.CertificateEnrolment.APPAUTH_USERNAME_POSITION);
NamedNodeMap appServerAttribute = userNameAuthPosition.getAttributes();
Node authNameNode = appServerAttribute.getNamedItem(PluginConstants.CertificateEnrolment.VALUE);
String userName = getRequestedUser(headerBst);
//CacheEntry cacheEntry = (CacheEntry) DeviceUtil.getCacheEntry(headerBst);
// String userName = cacheEntry.getUsername();
authNameNode.setTextContent(userName);
DeviceUtil.removeToken(headerBst);
String password = DeviceUtil.generateRandomToken();
Node passwordAuthPosition = wapParm.item(PluginConstants.CertificateEnrolment.APPAUTH_PASSWORD_POSITION);
NamedNodeMap appSrvPasswordAttribute = passwordAuthPosition.getAttributes();
Node authPasswordNode = appSrvPasswordAttribute.getNamedItem(PluginConstants.CertificateEnrolment.VALUE);
authPasswordNode.setTextContent(password);
String requestSecurityTokenResponse = SyncmlCredentialUtil.generateRST(userName, password);
DeviceUtil.persistChallengeToken(requestSecurityTokenResponse, null, userName);
// Get device polling frequency from the tenant Configurations.
Node numberOfFirstRetries = wapParm.item(PluginConstants.CertificateEnrolment.POLLING_FREQUENCY_POSITION);
NamedNodeMap pollingAttributes = numberOfFirstRetries.getAttributes();
Node pollValue = pollingAttributes.getNamedItem(PluginConstants.CertificateEnrolment.VALUE);
pollValue.setTextContent(pollingFrequency);
provisioningXmlString = convertDocumentToString(document);
} catch (ParserConfigurationException e) {
throw new WAPProvisioningException("Problem occurred while creating configuration request", e);
} catch (CertificateEncodingException e) {
throw new WindowsDeviceEnrolmentException("Error occurred while encoding certificates.", e);
} catch (SAXException e) {
throw new WAPProvisioningException("Error occurred while parsing wap-provisioning.xml file.", e);
} catch (TransformerException e) {
throw new WAPProvisioningException("Error occurred while transforming wap-provisioning.xml file.", e);
} catch (IOException e) {
throw new WAPProvisioningException("Error occurred while getting wap-provisioning.xml file.", e);
} catch (SyncmlMessageFormatException e) {
throw new WindowsDeviceEnrolmentException("Error occurred while generating password hash value.", e);
} catch (KeystoreException e) {
throw new CertificateGenerationException("CA certificate cannot be generated.", e);
}
return base64Encoder.encodeAsString(provisioningXmlString.getBytes());
}
/**
* This method get the soap request header contents.
*
* @return List of SOAP headers.
*/
private List<Header> getHeaders() {
MessageContext messageContext = context.getMessageContext();
if (messageContext == null || !(messageContext instanceof WrappedMessageContext)) {
return null;
}
Message message = ((WrappedMessageContext) messageContext).getWrappedMessage();
return CastUtils.cast((List<?>) message.get(Header.HEADER_LIST));
}
private String getRequestedUser(String bst) {
CacheEntry cacheEntry = (CacheEntry) DeviceUtil.getCacheEntry(bst);
String userName = cacheEntry.getUsername();
return userName;
}
private org.wso2.carbon.device.mgt.common.Device generateDevice(WindowsDevice windowsDevice) {
org.wso2.carbon.device.mgt.common.Device generatedDevice = new org.wso2.carbon.device.mgt.common.Device();
org.wso2.carbon.device.mgt.common.Device.Property DeviceNameProperty = new org.wso2.carbon.device.mgt.common.Device.Property();
DeviceNameProperty.setName(PluginConstants.SyncML.DEVICE_NAME);
DeviceNameProperty.setValue(windowsDevice.getDeviceName());
org.wso2.carbon.device.mgt.common.Device.Property OSVersionProperty = new org.wso2.carbon.device.mgt.common.Device.Property();
OSVersionProperty.setName(PluginConstants.SyncML.OS_VERSION);
OSVersionProperty.setValue(windowsDevice.getOsVersion());
org.wso2.carbon.device.mgt.common.Device.Property IMSEIProperty = new org.wso2.carbon.device.mgt.common.Device.Property();
IMSEIProperty.setName(PluginConstants.SyncML.IMSI);
IMSEIProperty.setValue(windowsDevice.getImsi());
org.wso2.carbon.device.mgt.common.Device.Property IMEIProperty = new org.wso2.carbon.device.mgt.common.Device.Property();
IMEIProperty.setName(PluginConstants.SyncML.IMEI);
IMEIProperty.setValue(windowsDevice.getImei());
List<org.wso2.carbon.device.mgt.common.Device.Property> propertyList = new ArrayList<>();
propertyList.add(OSVersionProperty);
propertyList.add(IMSEIProperty);
propertyList.add(IMEIProperty);
propertyList.add(DeviceNameProperty);
EnrolmentInfo enrolmentInfo = new EnrolmentInfo();
enrolmentInfo.setOwner(windowsDevice.getUser());
enrolmentInfo.setOwnership(EnrolmentInfo.OwnerShip.BYOD);
enrolmentInfo.setStatus(EnrolmentInfo.Status.ACTIVE);
generatedDevice.setEnrolmentInfo(enrolmentInfo);
generatedDevice.setDeviceIdentifier(windowsDevice.getDeviceId());
generatedDevice.setProperties(propertyList);
generatedDevice.setType(windowsDevice.getDeviceType());
return generatedDevice;
}
}

@ -0,0 +1,141 @@
/*
* 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.device.mgt.mobile.windows.api.services.enrollment.util;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.bouncycastle.asn1.x509.*;
import org.bouncycastle.cert.CertIOException;
import org.bouncycastle.cert.X509v3CertificateBuilder;
import org.bouncycastle.cert.jcajce.JcaX509CertificateConverter;
import org.bouncycastle.cert.jcajce.JcaX509v3CertificateBuilder;
import org.bouncycastle.operator.ContentSigner;
import org.bouncycastle.operator.OperatorCreationException;
import org.bouncycastle.operator.jcajce.JcaContentSignerBuilder;
import org.bouncycastle.pkcs.jcajce.JcaPKCS10CertificationRequest;
import org.wso2.carbon.device.mgt.mobile.windows.api.common.PluginConstants;
import org.wso2.carbon.device.mgt.mobile.windows.api.common.exceptions.CertificateGenerationException;
import org.wso2.carbon.device.mgt.mobile.windows.api.common.exceptions.WAPProvisioningException;
import javax.security.auth.x500.X500Principal;
import java.math.BigInteger;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.security.PrivateKey;
import java.security.SecureRandom;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import java.util.Date;
import java.util.List;
/**
* Class for generating signed certificate for CSR form device.
*/
public class CertificateSigningService {
private static final long MILLI_SECONDS = 1000L * 60 * 60 * 24;
private enum PropertyIndex {
COMMON_NAME_INDEX(0),
NOT_BEFORE_DAYS_INDEX(1),
NOT_AFTER_DAYS_INDEX(2);
private final int itemPosition;
private PropertyIndex(final int itemPosition) {
this.itemPosition = itemPosition;
}
public int getValue() {
return this.itemPosition;
}
}
private static Log log = LogFactory.getLog(
CertificateSigningService.class);
/**
* Implement certificate signing task using CSR received from the device and the MDM server key
* store.
* @param jcaRequest - CSR from the device
* @param privateKey - Private key of CA certificate in MDM server
* @param caCert - CA certificate in MDM server
* @param certParameterList - Parameter list for Signed certificate generation
* @return - Signed certificate for CSR from device
* @throws CertificateGenerationException
* @throws WAPProvisioningException
*/
public static X509Certificate signCSR(JcaPKCS10CertificationRequest jcaRequest,
PrivateKey privateKey, X509Certificate caCert,
List certParameterList) throws
CertificateGenerationException,
WAPProvisioningException {
String commonName =
(String) certParameterList.get(PropertyIndex.COMMON_NAME_INDEX.getValue());
int notBeforeDays =
(Integer) certParameterList.get(PropertyIndex.NOT_BEFORE_DAYS_INDEX.getValue());
int notAfterDays =
(Integer) certParameterList.get(PropertyIndex.NOT_AFTER_DAYS_INDEX.getValue());
X509v3CertificateBuilder certificateBuilder;
X509Certificate signedCertificate;
try {
ContentSigner signer;
BigInteger serialNumber = BigInteger.valueOf(new SecureRandom().
nextInt(Integer.MAX_VALUE));
Date notBeforeDate = new Date(System.currentTimeMillis() -
(MILLI_SECONDS * notBeforeDays));
Date notAfterDate = new Date(System.currentTimeMillis() +
(MILLI_SECONDS * notAfterDays));
certificateBuilder =
new JcaX509v3CertificateBuilder(caCert, serialNumber, notBeforeDate, notAfterDate,
new X500Principal(commonName),
jcaRequest.getPublicKey());
//Adding extensions to the signed certificate.
certificateBuilder.addExtension(Extension.keyUsage, true,
new KeyUsage(KeyUsage.digitalSignature));
certificateBuilder.addExtension(Extension.extendedKeyUsage, false,
new ExtendedKeyUsage(KeyPurposeId.id_kp_clientAuth));
certificateBuilder.addExtension(Extension.basicConstraints, true,
new BasicConstraints(false));
signer = new JcaContentSignerBuilder(PluginConstants.CertificateEnrolment.ALGORITHM).
setProvider(PluginConstants.CertificateEnrolment.PROVIDER).build(privateKey);
signedCertificate = new JcaX509CertificateConverter().setProvider(
PluginConstants.CertificateEnrolment.PROVIDER).getCertificate(
certificateBuilder.build(signer));
} catch (InvalidKeyException e) {
throw new CertificateGenerationException("CSR's public key is invalid", e);
} catch (NoSuchAlgorithmException e) {
throw new CertificateGenerationException("Certificate cannot be generated", e);
}
catch (CertIOException e) {
throw new CertificateGenerationException(
"Cannot add extension(s) to signed certificate", e);
}
catch (OperatorCreationException e) {
throw new CertificateGenerationException("Content signer cannot be created", e);
}
catch (CertificateException e) {
throw new CertificateGenerationException("Signed certificate cannot be generated", e);
}
return signedCertificate;
}
}

@ -0,0 +1,94 @@
/*
* 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.device.mgt.mobile.windows.api.services.enrollment.util;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.wso2.carbon.device.mgt.mobile.windows.api.common.PluginConstants;
import org.wso2.carbon.device.mgt.mobile.windows.api.common.exceptions.KeyStoreGenerationException;
import java.io.FileInputStream;
import java.io.IOException;
import java.security.KeyStore;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.cert.CertificateException;
/**
* Class for MDM Keystore operations.
*/
public class KeyStoreGenerator {
private static final Log log = LogFactory.getLog(
KeyStoreGenerator.class);
/**
* This method loads the MDM keystore.
* @param keyStore - MDM Keystore
* @param keyStorePassword - Keystore Password
* @param keyStorePath - Keystore path
* @throws KeyStoreGenerationException
*/
public static void loadToStore(KeyStore keyStore,
char[] keyStorePassword,
String keyStorePath) throws KeyStoreGenerationException {
FileInputStream fileInputStream = null;
try {
if (keyStorePath != null) {
fileInputStream = new FileInputStream(keyStorePath);
keyStore.load(fileInputStream, keyStorePassword);
}
} catch (NoSuchAlgorithmException e) {
throw new KeyStoreGenerationException(
"Requested cryptographic algorithm is not available in the environment.", e);
} catch (CertificateException e) {
throw new KeyStoreGenerationException("Error working with certificate related to, " +
keyStorePath, e);
} catch (IOException e) {
throw new KeyStoreGenerationException("File error while working with file, " +
keyStorePath, e);
} finally {
try {
if (fileInputStream != null) {
fileInputStream.close();
}
} catch (IOException e) {
throw new KeyStoreGenerationException("File error while closing the file, " +
keyStorePath, e);
}
}
}
/**
* This method is for retrieving instance of Key Store.
* @return Keystore object
* @throws KeyStoreGenerationException
*/
public static KeyStore getKeyStore() throws KeyStoreGenerationException {
try {
return KeyStore.getInstance(PluginConstants.CertificateEnrolment.JKS);
} catch (KeyStoreException e) {
String msg = "KeyStore error while creating new JKS.";
log.error(msg, e);
throw new KeyStoreGenerationException(msg, e);
}
}
}

@ -0,0 +1,200 @@
/*
* 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.device.mgt.mobile.windows.api.services.enrollment.util;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.joda.time.DateTime;
import org.joda.time.format.ISODateTimeFormat;
import org.wso2.carbon.device.mgt.mobile.windows.api.common.PluginConstants;
import javax.ws.rs.core.Response;
import javax.xml.namespace.QName;
import javax.xml.soap.*;
import javax.xml.ws.handler.MessageContext;
import javax.xml.ws.handler.soap.SOAPHandler;
import javax.xml.ws.handler.soap.SOAPMessageContext;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.*;
/**
* Class responsible for adding Timestamp security header in SOAP message and adding Content-length
* in the HTTP header for avoiding HTTP chunking.
*/
public class MessageHandler implements SOAPHandler<SOAPMessageContext> {
public static final String TIME_ZONE = "Z";
public static final int VALIDITY_TIME = 5;
public static final int TIMESTAMP_END_INDEX = 6;
public static final int TIMESTAMP_BEGIN_INDEX = 0;
private static Log log = LogFactory.getLog(
MessageHandler.class);
/**
* This method resolves the security header coming in the SOAP message.
* @return - Security Header
*/
@Override
public Set<QName> getHeaders() {
QName securityHeader = new QName(PluginConstants.WS_SECURITY_TARGET_NAMESPACE, PluginConstants.SECURITY);
HashSet<QName> headers = new HashSet<QName>();
headers.add(securityHeader);
return headers;
}
/**
* This method adds Timestamp for SOAP header, and adds Content-length for HTTP header for
* avoiding HTTP chunking.
*
* @param context - Context of the SOAP Message
*/
@Override
public boolean handleMessage(SOAPMessageContext context) {
Boolean outBoundProperty = (Boolean) context.get(MessageContext.MESSAGE_OUTBOUND_PROPERTY);
if (outBoundProperty) {
SOAPMessage message = context.getMessage();
SOAPHeader header = null;
SOAPEnvelope envelope = null;
try {
header = message.getSOAPHeader();
envelope = message.getSOAPPart().getEnvelope();
} catch (SOAPException e) {
Response.serverError().entity("SOAP message content cannot be read.").build();
}
try {
if ((header == null) && (envelope != null)) {
header = envelope.addHeader();
}
} catch (SOAPException e) {
Response.serverError().entity("SOAP header cannot be added.").build();
}
SOAPFactory soapFactory = null;
try {
soapFactory = SOAPFactory.newInstance();
} catch (SOAPException e) {
Response.serverError().entity("Cannot get an instance of SOAP factory.").build();
}
QName qNamesSecurity = new QName(PluginConstants.WS_SECURITY_TARGET_NAMESPACE,
PluginConstants.CertificateEnrolment.SECURITY);
SOAPHeaderElement Security = null;
Name attributeName = null;
try {
if (header != null) {
Security = header.addHeaderElement(qNamesSecurity);
}
if (soapFactory != null) {
attributeName =
soapFactory.createName(PluginConstants.CertificateEnrolment.TIMESTAMP_ID,
PluginConstants.CertificateEnrolment.TIMESTAMP_U,
PluginConstants.CertificateEnrolment
.WSS_SECURITY_UTILITY);
}
} catch (SOAPException e) {
Response.serverError().entity("Security header cannot be added.").build();
}
QName qNameTimestamp = new QName(PluginConstants.CertificateEnrolment.WSS_SECURITY_UTILITY,
PluginConstants.CertificateEnrolment.TIMESTAMP);
SOAPHeaderElement timestamp = null;
try {
if (header != null) {
timestamp = header.addHeaderElement(qNameTimestamp);
timestamp.addAttribute(attributeName,
PluginConstants.CertificateEnrolment.TIMESTAMP_0);
}
} catch (SOAPException e) {
Response.serverError().entity("Exception while adding timestamp header.").build();
}
DateTime dateTime = new DateTime();
DateTime expiredDateTime = dateTime.plusMinutes(VALIDITY_TIME);
String createdISOTime = dateTime.toString(ISODateTimeFormat.dateTime());
String expiredISOTime = expiredDateTime.toString(ISODateTimeFormat.dateTime());
createdISOTime = createdISOTime.substring(TIMESTAMP_BEGIN_INDEX,
createdISOTime.length() -
TIMESTAMP_END_INDEX);
createdISOTime = createdISOTime + TIME_ZONE;
expiredISOTime = expiredISOTime.substring(TIMESTAMP_BEGIN_INDEX,
expiredISOTime.length() -
TIMESTAMP_END_INDEX);
expiredISOTime = expiredISOTime + TIME_ZONE;
QName qNameCreated = new QName(PluginConstants.CertificateEnrolment.WSS_SECURITY_UTILITY,
PluginConstants.CertificateEnrolment.CREATED);
SOAPHeaderElement SOAPHeaderCreated = null;
try {
if (header != null) {
SOAPHeaderCreated = header.addHeaderElement(qNameCreated);
SOAPHeaderCreated.addTextNode(createdISOTime);
}
} catch (SOAPException e) {
Response.serverError().entity("Exception while creating SOAP header.").build();
}
QName qNameExpires = new QName(PluginConstants.CertificateEnrolment.WSS_SECURITY_UTILITY,
PluginConstants.CertificateEnrolment.EXPIRES);
SOAPHeaderElement SOAPHeaderExpires = null;
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
String messageString = null;
try {
if (header != null) {
SOAPHeaderExpires = header.addHeaderElement(qNameExpires);
SOAPHeaderExpires.addTextNode(expiredISOTime);
}
if ((timestamp != null) && (Security != null)) {
timestamp.addChildElement(SOAPHeaderCreated);
timestamp.addChildElement(SOAPHeaderExpires);
Security.addChildElement(timestamp);
}
message.saveChanges();
message.writeTo(outputStream);
messageString = new String(outputStream.toByteArray(),
PluginConstants.CertificateEnrolment.UTF_8);
} catch (SOAPException e) {
Response.serverError().entity("Exception while creating timestamp SOAP header.")
.build();
} catch (IOException e) {
Response.serverError().entity("Exception while writing message to output stream.")
.build();
}
Map<String, List<String>> headers =
(Map<String, List<String>>) context.get(MessageContext.HTTP_REQUEST_HEADERS);
headers = new HashMap<String, List<String>>();
if (messageString != null) {
headers.put(PluginConstants.CONTENT_LENGTH, Arrays.asList(String.valueOf(
messageString.length())));
}
context.put(MessageContext.HTTP_REQUEST_HEADERS, headers);
}
return true;
}
@Override
public boolean handleFault(SOAPMessageContext context) {
return true;
}
@Override
public void close(MessageContext context) {
}
}

@ -31,6 +31,7 @@ public class WindowsDevice {
private String manufacturer;
private String model;
private String user;
private String deviceName;
public String getImei() {
return imei;
@ -96,5 +97,13 @@ public class WindowsDevice {
this.user = user;
}
public String getDeviceName() {
return deviceName;
}
public void setDeviceName(String deviceName) {
this.deviceName = deviceName;
}
}

@ -320,19 +320,14 @@ public class SyncmlServiceImpl implements SyncmlService {
macAddressProperty.setValue(macAddress);
existingProperties.add(macAddressProperty);
// Device.Property resolutionProperty = new Device.Property();
// resolutionProperty.setName(PluginConstants.SyncML.DEVICE_INFO);
// resolutionProperty.setValue("null");
// existingProperties.add(resolutionProperty);
Device.Property deviceNameProperty = new Device.Property();
deviceNameProperty.setName(PluginConstants.SyncML.DEVICE_NAME);
deviceNameProperty.setValue(deviceName);
existingProperties.add(deviceNameProperty);
Device.Property deviceModelProperty = new Device.Property();
deviceNameProperty.setName(PluginConstants.SyncML.MODEL);
deviceNameProperty.setValue(devMod);
deviceModelProperty.setName(PluginConstants.SyncML.MODEL);
deviceModelProperty.setValue(devMod);
existingProperties.add(deviceModelProperty);
existingDevice.setProperties(existingProperties);

@ -59,24 +59,27 @@
</jaxws:handlers>
</jaxws:endpoint>
<!--XCEP endpoint for OnPremise Auth-Policy-->
<!--WSTEP Endpoint for Federated Auth-Policy-->
<jaxws:endpoint
id="EnrollmentPolicyServiceOnPremise"
implementor="org.wso2.carbon.device.mgt.mobile.windows.api.services.xcep.impl.CertificateEnrollmentPolicyServiceImpl"
address="/certificatepolicy/xcep/onpremise">
id="CertificateEnrollmentService"
implementor="org.wso2.carbon.device.mgt.mobile.windows.api.services.wstep.impl.CertificateEnrollmentServiceImpl"
address="/deviceenrolment/wstep">
<jaxws:properties>
<entry key="ws-security.ut.validator" value-ref="customvalidatoronpremise"/>
<entry key="ws-security.bst.validator" value-ref="customvalidator"/>
</jaxws:properties>
<jaxws:inInterceptors>
<ref bean="wss4jInInterceptor"/>
<ref bean="wss4jInInterceptor_federated"/>
</jaxws:inInterceptors>
<jaxws:handlers>
<ref bean="serviceOptionsHandler"/>
</jaxws:handlers>
</jaxws:endpoint>
<!--WSTEP Endpoint for Federated Auth-Policy-->
<!-- Enrollment Endpoint for windows 10 -->
<jaxws:endpoint
id="CertificateEnrollmentService"
implementor="org.wso2.carbon.device.mgt.mobile.windows.api.services.wstep.impl.CertificateEnrollmentServiceImpl"
address="/deviceenrolment/wstep">
id="EnrollmentService"
implementor="org.wso2.carbon.device.mgt.mobile.windows.api.services.enrollment.impl.EnrollmentServiceImpl"
address="/deviceenrolment/enrollment">
<jaxws:properties>
<entry key="ws-security.bst.validator" value-ref="customvalidator"/>
</jaxws:properties>

@ -67,6 +67,7 @@
<context-param>
<param-name>nonSecuredEndPoints</param-name>
<param-value>/services/discovery/get,/services/discovery/post,/services/certificatepolicy/xcep,
,/services/deviceenrolment/wstep,/services/syncml/devicemanagement/request</param-value>
,/services/deviceenrolment/wstep,/services/syncml/devicemanagement/request,/services/deviceenrolment/enrollment
</param-value>
</context-param>
</web-app>

@ -0,0 +1,127 @@
{{!
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.
}}
{{#if control_operations}}
<div class="wr-operations" style="height: 87px; display: block;">
<style>
::-webkit-input-placeholder {
color: #B8B8B8;
}
::-moz-placeholder {
color: #B8B8B8;
}
:-ms-input-placeholder {
color: #B8B8B8;
}
input:-moz-placeholder {
color: #B8B8B8;
}
</style>
{{#each control_operations}}
<a href="javascript:operationSelect('{{operation}}')">
{{#if iconFont}}
<i class="fw {{iconFont}}"></i>
{{else}}
{{#if icon}}
<img src="{{@app.context}}/{{icon}}" style="width: 48px;"/>
{{else}}
<i class="fw fw-service"></i>
{{/if}}
{{/if}}
<span>{{name}}</span>
</a>
<div class="operation" data-operation-code="{{operation}}">
<div class="content">
<div class="row">
<div class="col-lg-5 col-md-6 col-centered">
<h3>
<span class="fw-stack">
<i class="fw fw-ring fw-stack-2x"></i>
<i class="fw fw-service fw-stack-1x"></i>
</span>
{{name}}
<br>
</h3>
<h4>
{{description}}
<br>
</h4>
<form action="{{params.0.uri}}" method="{{params.0.method}}"
style="padding-bottom: 20px;"
data-payload="{{payload}}" id="form-{{operation}}"
data-device-id="{{../device.deviceIdentifier}}">
{{#each params.0.pathParams}}
<input type="{{type}}" id="{{name}}" placeholder="{{name}}" class="form-control" data-param-type="path" value="{{value}}" />
<br />
{{/each}}
{{#each params.0.formParams}}
<input type="{{type}}" id="{{name}}" name="{{name}}" placeholder="{{name}}" class="form-control" data-param-type="form" value="{{value}}" />
<br />
{{/each}}
{{#each params.0.queryParams}}
<input type="{{type}}" id="{{name}}" placeholder="{{name}}" class="form-control" data-param-type="query" value="{{value}}" />
<br />
{{/each}}
<button id="btnSend" type="button" onclick="submitForm('form-{{operation}}')" class="btn btn-default">&nbsp;&nbsp;&nbsp;&nbsp;Send
to Device&nbsp;&nbsp;&nbsp;&nbsp;</button>
<label id="lblSending" class="wr-input-label hidden"><i
class="fw fw-lifecycle fw-spin fw-2x"></i> Sending..</label>
<label id="lblSent" class="wr-input-label hidden"><i
class="fw fw-check fw-2x"></i> Sent</label>
</form>
</div>
</div>
</div>
</div>
{{/each}}
</div>
{{else}}
<div align="center">
<h4 style="color: #D8000C"><i class="icon fw fw-error" style="color: #D8000C"></i>
Operations Loading Failed!</h4>
</div>
{{/if}}
<div id="operation-response-template" style="display: none">
<div class="content">
<div class="row">
<div class="col-lg-5 col-md-6 col-centered">
<h3>
<span class="fw-stack">
<i class="fw fw-ring fw-stack-2x"></i>
<i id="status-icon" class="fw fw-error fw-stack-1x"></i>
</span>
<br>
</h3>
<h4>
<span id="title"></span>
<br>
</h4>
<span id="description"></span>
</div>
</div>
</div>
</div>
{{#zone "bottomJs"}}
{{js "js/operation-bar.js"}}
{{/zone}}

@ -0,0 +1,67 @@
/*
* 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.
*/
function onRequest(context) {
var log = new Log("operation.js");
var operationModule = require("/app/modules/business-controllers/operation.js")["operationModule"];
var device = context.unit.params.device;
var autoCompleteParams = context.unit.params.autoCompleteParams;
var encodedFeaturePayloads=context.unit.params.encodedFeaturePayloads;
var controlOperations = operationModule.getControlOperations(device.type);
var queryParams = [];
var formParams = [];
var pathParams = [];
for (var i = 0; i < controlOperations.length; i++) {
var currentParamList = controlOperations[i]["params"];
for (var j = 0; j < currentParamList.length; j++) {
var currentParam = currentParamList[j];
currentParamList[j]["formParams"] = processParams(currentParam["formParams"], autoCompleteParams);
currentParamList[j]["queryParams"] = processParams(currentParam["queryParams"], autoCompleteParams);
currentParamList[j]["pathParams"] = processParams(currentParam["pathParams"], autoCompleteParams);
}
controlOperations[i]["params"] = currentParamList;
if (encodedFeaturePayloads) {
controlOperations[i]["payload"] = getPayload(encodedFeaturePayloads, controlOperations[i]["operation"]);
}
}
return {"control_operations": controlOperations, "device": device};
}
function processParams(paramsList, autoCompleteParams) {
var log = new Log();
log.info("-- Params : "+paramsList.length);
log.info("-- Auto Params : "+autoCompleteParams);
for (var i = 0; i < paramsList.length; i++) {
var paramName = paramsList[i];
var paramValue = "";
var paramType = "text";
for (var k = 0; k < autoCompleteParams.length; k++) {
if (paramName == autoCompleteParams[k].name) {
paramValue = autoCompleteParams[k].value;
paramType = "hidden";
}
}
paramsList[i] = {"name": paramName, "value": paramValue, "type": paramType};
}
return paramsList;
}
function getPayload(featuresPayload, featureCode){
var featuresJSONPayloads = JSON.parse(featuresPayload);
return featuresJSONPayloads[featureCode];
}

@ -0,0 +1,146 @@
/*
* 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.
*/
/*
* On operation click function.
* @param selection: Selected operation
*/
function operationSelect(selection) {
$(modalPopupContent).addClass("operation-data");
$(modalPopupContent).html($(" .operation[data-operation-code=" + selection + "]").html());
$(modalPopupContent).data("operation-code", selection);
showPopup();
}
function submitForm(formId) {
var form = $("#" + formId);
var uri = form.attr("action");
var deviceId = form.data("device-id");
var uriencodedQueryStr = "";
var uriencodedFormStr = "";
var payload = {};
form.find("input").each(function () {
var input = $(this);
if (input.data("param-type") == "path") {
uri = uri.replace("{" + input.attr("id") + "}", input.val());
} else if (input.data("param-type") == "query") {
var prefix = (uriencodedQueryStr == "") ? "?" : "&";
uriencodedQueryStr += prefix + input.attr("id") + "=" + input.val();
} else if (input.data("param-type") == "form") {
var prefix = (uriencodedFormStr == "") ? "" : "&";
uriencodedFormStr += prefix + input.attr("id") + "=" + input.val();
//payload[input.attr("id")] = input.val();
}
});
uri += uriencodedQueryStr;
var httpMethod = form.attr("method").toUpperCase();
var contentType = form.attr("enctype");
console.log("URL "+uri);
console.log("Method "+httpMethod);
console.log("Content Type "+contentType);
var featurePayload = form.attr("data-payload");
if (featurePayload) {
contentType = "application/json";
payload = JSON.parse(atob(featurePayload));
} else if (contentType == undefined || contentType.isEmpty()) {
contentType = "application/x-www-form-urlencoded";
payload = uriencodedFormStr;
}
//setting responses callbacks
var defaultStatusClasses = "fw fw-stack-1x";
var content = $("#operation-response-template").find(".content");
var title = content.find("#title");
var statusIcon = content.find("#status-icon");
var description = content.find("#description");
description.html("");
var successCallBack = function (response) {
var res = response;
try {
res = JSON.parse(response).messageFromServer;
} catch (err) {
//do nothing
}
title.html("Operation Triggered!");
statusIcon.attr("class", defaultStatusClasses + " fw-check");
description.html(res);
console.log("success!");
$(modalPopupContent).html(content.html());
};
var errorCallBack = function (response) {
console.log(response);
title.html("An Error Occurred!");
statusIcon.attr("class", defaultStatusClasses + " fw-error");
var reason = (response.responseText == "null")?response.statusText:response.responseText;
try {
reason = JSON.parse(reason).message;
} catch (err) {
//do nothing
}
description.html(reason);
console.log("Error!");
$(modalPopupContent).html(content.html());
};
//executing http request
if (httpMethod == "GET") {
invokerUtil.get(uri, successCallBack, errorCallBack, contentType);
} else if (httpMethod == "POST") {
console.log("------ cType "+contentType);
var payloadTest = [deviceId];
invokerUtil.post(uri, payloadTest, successCallBack, errorCallBack, "application/json");
} else if (httpMethod == "PUT") {
invokerUtil.put(uri, payload, successCallBack, errorCallBack, contentType);
} else if (httpMethod == "DELETE") {
invokerUtil.delete(uri, successCallBack, errorCallBack, contentType);
} else {
title.html("An Error Occurred!");
statusIcon.attr("class", defaultStatusClasses + " fw-error");
description.html("This operation requires http method: " + httpMethod + " which is not supported yet!");
$(modalPopupContent).html(content.html());
}
}
$(document).on('submit', 'form', function (e) {
cosole.log("darn!!");
e.preventDefault();
var postOperationRequest = $.ajax({
url: $(this).attr("action") + '&' + $(this).serialize(),
method: "post"
});
var btnSubmit = $('#btnSend', this);
btnSubmit.addClass('hidden');
var lblSending = $('#lblSending', this);
lblSending.removeClass('hidden');
var lblSent = $('#lblSent', this);
postOperationRequest.done(function (data) {
lblSending.addClass('hidden');
lblSent.removeClass('hidden');
setTimeout(function () {
hidePopup();
}, 3000);
});
postOperationRequest.fail(function (jqXHR, textStatus) {
lblSending.addClass('hidden');
lblSent.addClass('hidden');
});
});

@ -22,6 +22,7 @@ org.eclipse.equinox.p2.touchpoint.natives.remove(path:${installFolder}/../../dep
org.eclipse.equinox.p2.touchpoint.natives.remove(path:${installFolder}/../../deployment/server/jaggeryapps/devicemgt/app/units/cdmf.unit.device.type.windows.type-view);\
org.eclipse.equinox.p2.touchpoint.natives.remove(path:${installFolder}/../../deployment/server/jaggeryapps/devicemgt/app/units/cdmf.unit.device.type.windows.leaflet);\
org.eclipse.equinox.p2.touchpoint.natives.remove(path:${installFolder}/../../deployment/server/jaggeryapps/devicemgt/app/units/cdmf.unit.device.type.windows.operation-bar);\
org.eclipse.equinox.p2.touchpoint.natives.remove(path:${installFolder}/../../deployment/server/jaggeryapps/devicemgt/app/units/cdmf.unit.device.type.windows.new.operation-bar);\
org.eclipse.equinox.p2.touchpoint.natives.remove(path:${installFolder}/../../deployment/server/jaggeryapps/devicemgt/app/units/cdmf.unit.device.type.windows.operation-mod);\
org.eclipse.equinox.p2.touchpoint.natives.remove(path:${installFolder}/../../deployment/server/jaggeryapps/devicemgt/app/units/cdmf.unit.device.type.windows.date-range-picker);\
org.eclipse.equinox.p2.touchpoint.natives.remove(path:${installFolder}/../../../dbscripts/cdm/plugins/windows);\

Loading…
Cancel
Save