Merge branch 'tenant-improve' into 'tenant-improve'

Modify invite-user API to have enrollment steps included in the mail and add OTP token as query param

See merge request entgra/carbon-device-mgt!619
revert-70ac1926
Dharmakeerthi Lasantha 4 years ago
commit 7f7fbf21b4

@ -49,6 +49,7 @@ import io.swagger.annotations.ResponseHeader;
import org.apache.axis2.transport.http.HTTPConstants;
import org.wso2.carbon.apimgt.annotations.api.Scopes;
import org.wso2.carbon.apimgt.annotations.api.Scope;
import org.wso2.carbon.device.mgt.common.invitation.mgt.DeviceEnrollmentInvitation;
import org.wso2.carbon.device.mgt.jaxrs.beans.ActivityList;
import org.wso2.carbon.device.mgt.jaxrs.beans.BasicUserInfo;
import org.wso2.carbon.device.mgt.jaxrs.beans.BasicUserInfoList;
@ -74,7 +75,6 @@ import javax.ws.rs.Produces;
import javax.ws.rs.QueryParam;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import java.util.List;
@SwaggerDefinition(
info = @Info(
@ -893,7 +893,8 @@ public interface UserManagementService {
@ApiParam(
name = "users",
value = "List of users",
required = true) List<String> usernames);
required = true)
@Valid DeviceEnrollmentInvitation deviceEnrollmentInvitation);
@POST
@Path("/enrollment-invite")

@ -45,8 +45,11 @@ import org.wso2.carbon.context.PrivilegedCarbonContext;
import org.wso2.carbon.device.mgt.common.exceptions.DeviceManagementException;
import org.wso2.carbon.device.mgt.common.EnrolmentInfo;
import org.wso2.carbon.device.mgt.common.configuration.mgt.ConfigurationManagementException;
import org.wso2.carbon.device.mgt.common.exceptions.OTPManagementException;
import org.wso2.carbon.device.mgt.common.invitation.mgt.DeviceEnrollmentInvitation;
import org.wso2.carbon.device.mgt.common.operation.mgt.Activity;
import org.wso2.carbon.device.mgt.common.operation.mgt.OperationManagementException;
import org.wso2.carbon.device.mgt.common.spi.OTPManagementService;
import org.wso2.carbon.device.mgt.core.DeviceManagementConstants;
import org.wso2.carbon.device.mgt.core.service.DeviceManagementProviderService;
import org.wso2.carbon.device.mgt.core.service.EmailMetaInfo;
@ -716,48 +719,29 @@ public class UserManagementServiceImpl implements UserManagementService {
return CredentialManagementResponseBuilder.buildChangePasswordResponse(credentials);
}
/**
* Method used to send an invitation email to a existing user to enroll a device.
*
* @param usernames Username list of the users to be invited
*/
@POST
@Path("/send-invitation")
@Produces({MediaType.APPLICATION_JSON})
public Response inviteExistingUsersToEnrollDevice(List<String> usernames) {
public Response inviteExistingUsersToEnrollDevice(DeviceEnrollmentInvitation deviceEnrollmentInvitation) {
if (deviceEnrollmentInvitation.getUsernames() == null || deviceEnrollmentInvitation.getUsernames().isEmpty()) {
String msg = "Error occurred while validating list of user-names. User-names cannot be empty.";
log.error(msg);
throw new BadRequestException(
new ErrorResponse.ErrorResponseBuilder().setCode(HttpStatus.SC_BAD_REQUEST).setMessage(msg)
.build());
}
if (log.isDebugEnabled()) {
log.debug("Sending enrollment invitation mail to existing user.");
log.debug("Sending device enrollment invitation mail to existing user/s.");
}
DeviceManagementProviderService dms = DeviceMgtAPIUtils.getDeviceManagementService();
OTPManagementService oms = DeviceMgtAPIUtils.getOTPManagementService();
try {
for (String username : usernames) {
String recipient = getClaimValue(username, Constants.USER_CLAIM_EMAIL_ADDRESS);
Properties props = new Properties();
props.setProperty("first-name", getClaimValue(username, Constants.USER_CLAIM_FIRST_NAME));
props.setProperty("username", username);
EmailMetaInfo metaInfo = new EmailMetaInfo(recipient, props);
dms.sendEnrolmentInvitation(DeviceManagementConstants.EmailAttributes.USER_ENROLLMENT_TEMPLATE,
metaInfo);
}
} catch (DeviceManagementException e) {
String msg = "Error occurred while inviting user to enrol their device";
if (e.getMessage() != null && !e.getMessage().isEmpty()) {
msg = e.getMessage();
}
log.error(msg, e);
return Response.serverError().entity(
new ErrorResponse.ErrorResponseBuilder().setMessage(msg).build()).build();
} catch (UserStoreException e) {
String msg = "Error occurred while getting claim values to invite user";
oms.sendDeviceEnrollmentInvitationMail(deviceEnrollmentInvitation);
} catch (OTPManagementException e) {
String msg = "Error occurred while generating OTP and inviting user/s to enroll their device/s.";
log.error(msg, e);
return Response.serverError().entity(
new ErrorResponse.ErrorResponseBuilder().setMessage(msg).build()).build();
} catch (ConfigurationManagementException e) {
String msg = "Error occurred while sending the email invitations. Mail server not configured.";
return Response.serverError().entity(
new ErrorResponse.ErrorResponseBuilder().setMessage(msg).build()).build();
}
return Response.status(Response.Status.OK).entity("Invitation mails have been sent.").build();
}

@ -14,6 +14,23 @@
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*
*
* Copyright (c) 2020, Entgra (Pvt) Ltd. (http://www.entgra.io) All Rights Reserved.
*
* Entgra (Pvt) Ltd. 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.jaxrs.util;
@ -142,6 +159,7 @@ public class DeviceMgtAPIUtils {
private static IntegrationClientService integrationClientService;
private static MetadataManagementService metadataManagementService;
private static OTPManagementService otpManagementService;
static {
String keyStorePassword = ServerConfiguration.getInstance().getFirstProperty("Security.KeyStore.Password");
@ -338,6 +356,25 @@ public class DeviceMgtAPIUtils {
return integrationClientService;
}
/**
* Initializing and accessing method for OTPManagementService.
*
* @return OTPManagementService instance
* @throws IllegalStateException if OTPManagementService cannot be initialized
*/
public static synchronized OTPManagementService getOTPManagementService() {
if (otpManagementService == null) {
PrivilegedCarbonContext ctx = PrivilegedCarbonContext.getThreadLocalCarbonContext();
otpManagementService = (OTPManagementService) ctx.getOSGiService(OTPManagementService.class, null);
if (otpManagementService == null) {
String msg = "OTP Management service has not initialized.";
log.error(msg);
throw new IllegalStateException(msg);
}
}
return otpManagementService;
}
public static RegistryService getRegistryService() {
RegistryService registryService;
PrivilegedCarbonContext ctx = PrivilegedCarbonContext.getThreadLocalCarbonContext();

@ -15,6 +15,23 @@
* specific language governing permissions and limitations
* under the License.
*
*
* Copyright (c) 2020, Entgra (Pvt) Ltd. (http://www.entgra.io) All Rights Reserved.
*
* Entgra (Pvt) Ltd. 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.jaxrs.service.impl;
@ -34,6 +51,10 @@ import org.testng.annotations.Test;
import org.wso2.carbon.context.CarbonContext;
import org.wso2.carbon.device.mgt.common.exceptions.DeviceManagementException;
import org.wso2.carbon.device.mgt.common.configuration.mgt.ConfigurationManagementException;
import org.wso2.carbon.device.mgt.common.exceptions.OTPManagementException;
import org.wso2.carbon.device.mgt.common.invitation.mgt.DeviceEnrollmentInvitation;
import org.wso2.carbon.device.mgt.common.spi.OTPManagementService;
import org.wso2.carbon.device.mgt.core.otp.mgt.service.OTPManagementServiceImpl;
import org.wso2.carbon.device.mgt.core.service.DeviceManagementProviderService;
import org.wso2.carbon.device.mgt.core.service.DeviceManagementProviderServiceImpl;
import org.wso2.carbon.device.mgt.jaxrs.beans.BasicUserInfo;
@ -66,9 +87,11 @@ public class UserManagementServiceImplTest {
private UserStoreManager userStoreManager;
private UserManagementService userManagementService;
private DeviceManagementProviderService deviceManagementProviderService;
private OTPManagementService otpManagementService;
private static final String DEFAULT_DEVICE_USER = "Internal/devicemgt-user";
private UserRealm userRealm;
private EnrollmentInvitation enrollmentInvitation;
private DeviceEnrollmentInvitation deviceEnrollmentInvitation;
private List<String> userList;
private static final String TEST_USERNAME = "test";
private static final String TEST2_USERNAME = "test2";
@ -86,6 +109,7 @@ public class UserManagementServiceImplTest {
userStoreManager = Mockito.mock(UserStoreManager.class, Mockito.RETURNS_MOCKS);
deviceManagementProviderService = Mockito
.mock(DeviceManagementProviderServiceImpl.class, Mockito.CALLS_REAL_METHODS);
otpManagementService = Mockito.mock(OTPManagementServiceImpl.class, Mockito.CALLS_REAL_METHODS);
userRealm = Mockito.mock(UserRealm.class);
RealmConfiguration realmConfiguration = Mockito.mock(RealmConfiguration.class);
Mockito.doReturn(null).when(realmConfiguration).getSecondaryRealmConfig();
@ -97,6 +121,8 @@ public class UserManagementServiceImplTest {
enrollmentInvitation.setRecipients(recipients);
userList = new ArrayList<>();
userList.add(TEST_USERNAME);
deviceEnrollmentInvitation = new DeviceEnrollmentInvitation();
deviceEnrollmentInvitation.setUsernames(userList);
}
@Test(description = "This method tests the addUser method of UserManagementService")
@ -205,13 +231,11 @@ public class UserManagementServiceImplTest {
@Test(description = "This method tests the send invitation method of UserManagementService", dependsOnMethods =
{"testIsUserExists"})
public void testSendInvitation() throws ConfigurationManagementException, DeviceManagementException {
PowerMockito.stub(PowerMockito.method(DeviceMgtAPIUtils.class, "getUserStoreManager"))
.toReturn(this.userStoreManager);
PowerMockito.stub(PowerMockito.method(DeviceMgtAPIUtils.class, "getDeviceManagementService"))
.toReturn(this.deviceManagementProviderService);
Mockito.doNothing().when(deviceManagementProviderService).sendEnrolmentInvitation(Mockito.any(), Mockito.any());
Response response = userManagementService.inviteExistingUsersToEnrollDevice(userList);
public void testSendInvitation() throws OTPManagementException {
PowerMockito.stub(PowerMockito.method(DeviceMgtAPIUtils.class, "getOTPManagementService"))
.toReturn(this.otpManagementService);
Mockito.doNothing().when(otpManagementService).sendDeviceEnrollmentInvitationMail(Mockito.any());
Response response = userManagementService.inviteExistingUsersToEnrollDevice(deviceEnrollmentInvitation);
Assert.assertEquals(response.getStatus(), Response.Status.OK.getStatusCode(),
"Inviting existing users to enroll device failed");
}
@ -240,7 +264,7 @@ public class UserManagementServiceImplTest {
@Test(description = "This method tests the inviteToEnrollDevice method of UserManagementService",
dependsOnMethods = "testGetUsers")
public void testInviteToEnrollDevice() {
public void testInviteToEnrollDevice() throws ConfigurationManagementException, DeviceManagementException {
URL resourceUrl = ClassLoader.getSystemResource("testng.xml");
System.setProperty("carbon.home", resourceUrl.getPath());
PowerMockito.stub(PowerMockito.method(DeviceMgtAPIUtils.class, "getUserStoreManager"))
@ -248,6 +272,7 @@ public class UserManagementServiceImplTest {
PowerMockito.stub(PowerMockito.method(DeviceMgtAPIUtils.class, "getAuthenticatedUser")).toReturn(TEST_USERNAME);
PowerMockito.stub(PowerMockito.method(DeviceMgtAPIUtils.class, "getDeviceManagementService"))
.toReturn(this.deviceManagementProviderService);
Mockito.doNothing().when(deviceManagementProviderService).sendEnrolmentInvitation(Mockito.any(), Mockito.any());
EnrollmentInvitation enrollmentInvitation = new EnrollmentInvitation();
List<String> recipients = new ArrayList<>();
recipients.add(TEST_USERNAME);
@ -289,16 +314,22 @@ public class UserManagementServiceImplTest {
@Test(description = "This method tests the behaviour of methods when there is an issue with "
+ "DeviceManagementProviderService", dependsOnMethods = {"testGetUserCount"})
public void testNegativeScenarios1() throws ConfigurationManagementException, DeviceManagementException {
public void testNegativeScenarios1()
throws ConfigurationManagementException, DeviceManagementException, OTPManagementException {
PowerMockito.stub(PowerMockito.method(DeviceMgtAPIUtils.class, "getUserStoreManager"))
.toReturn(this.userStoreManager);
PowerMockito.stub(PowerMockito.method(DeviceMgtAPIUtils.class, "getDeviceManagementService"))
.toReturn(this.deviceManagementProviderService);
PowerMockito.stub(PowerMockito.method(DeviceMgtAPIUtils.class, "getAuthenticatedUser")).toReturn(TEST_USERNAME);
Mockito.reset(deviceManagementProviderService);
PowerMockito.stub(PowerMockito.method(DeviceMgtAPIUtils.class, "getOTPManagementService"))
.toReturn(this.otpManagementService);
Mockito.reset(otpManagementService);
Mockito.doThrow(new DeviceManagementException()).when(deviceManagementProviderService)
.sendEnrolmentInvitation(Mockito.any(), Mockito.any());
Response response = userManagementService.inviteExistingUsersToEnrollDevice(userList);
Mockito.doThrow(new OTPManagementException()).when(otpManagementService)
.sendDeviceEnrollmentInvitationMail(Mockito.any());
Response response = userManagementService.inviteExistingUsersToEnrollDevice(deviceEnrollmentInvitation);
Assert.assertEquals(response.getStatus(), Response.Status.INTERNAL_SERVER_ERROR.getStatusCode(),
"Invite existing users to enroll device succeeded under erroneous conditions");
response = userManagementService.inviteToEnrollDevice(enrollmentInvitation);
@ -346,6 +377,8 @@ public class UserManagementServiceImplTest {
PowerMockito.stub(PowerMockito.method(DeviceMgtAPIUtils.class, "getDeviceManagementService"))
.toReturn(this.deviceManagementProviderService);
Mockito.reset(this.userStoreManager);
PowerMockito.stub(PowerMockito.method(DeviceMgtAPIUtils.class, "getOTPManagementService"))
.toReturn(this.otpManagementService);
Mockito.doThrow(new UserStoreException()).when(userStoreManager)
.getUserClaimValue(Mockito.any(), Mockito.any(), Mockito.any());
Mockito.doThrow(new UserStoreException()).when(userStoreManager)
@ -362,7 +395,7 @@ public class UserManagementServiceImplTest {
response = userManagementService.inviteToEnrollDevice(enrollmentInvitation);
Assert.assertEquals(response.getStatus(), Response.Status.INTERNAL_SERVER_ERROR.getStatusCode(),
"Invite existing users to enroll device succeeded under erroneous conditions");
response = userManagementService.inviteExistingUsersToEnrollDevice(userList);
response = userManagementService.inviteExistingUsersToEnrollDevice(deviceEnrollmentInvitation);
Assert.assertEquals(response.getStatus(), Response.Status.INTERNAL_SERVER_ERROR.getStatusCode(),
"Invite existing users to enroll device succeeded under erroneous conditions");
}

@ -0,0 +1,59 @@
/* Copyright (c) 2020, Entgra (Pvt) Ltd. (http://www.entgra.io) All Rights Reserved.
*
* Entgra (Pvt) Ltd. 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.common.invitation.mgt;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import java.io.Serializable;
import java.util.List;
@ApiModel(
value = "DeviceEnrollmentInvitation",
description = "Holds data to send device enrollment invitation to list of existing users.")
public class DeviceEnrollmentInvitation implements Serializable {
private static final long serialVersionUID = 6933837278652532052L;
@ApiModelProperty(
name = "usernames",
value = "List of usernames of users.",
required = true)
private List<String> usernames;
@ApiModelProperty(
name = "deviceEnrollmentTypes",
value = "List of enrollment types against device types.")
private List<DeviceEnrollmentType> deviceEnrollmentTypes;
public List<String> getUsernames() {
return usernames;
}
public void setUsernames(List<String> usernames) {
this.usernames = usernames;
}
public List<DeviceEnrollmentType> getDeviceEnrollmentTypes() {
return deviceEnrollmentTypes;
}
public void setDeviceEnrollmentTypes(
List<DeviceEnrollmentType> deviceEnrollmentTypes) {
this.deviceEnrollmentTypes = deviceEnrollmentTypes;
}
}

@ -0,0 +1,25 @@
package org.wso2.carbon.device.mgt.common.invitation.mgt;
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.List;
@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "DeviceEnrollmentInvitationDetails", propOrder = {
"enrollmentDetails"
})
public class DeviceEnrollmentInvitationDetails {
@XmlElement(name = "EnrollmentDetails")
private List<EnrollmentDetails> enrollmentDetails;
public List<EnrollmentDetails> getEnrollmentDetails() {
return enrollmentDetails;
}
public void setEnrollmentDetails(List<EnrollmentDetails> enrollmentDetails) {
this.enrollmentDetails = enrollmentDetails;
}
}

@ -0,0 +1,59 @@
/* Copyright (c) 2020, Entgra (Pvt) Ltd. (http://www.entgra.io) All Rights Reserved.
*
* Entgra (Pvt) Ltd. 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.common.invitation.mgt;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import java.io.Serializable;
import java.util.List;
@ApiModel(
value = "DeviceEnrollmentType",
description = "Holds data of enrollment types against device types.")
public class DeviceEnrollmentType implements Serializable {
private static final long serialVersionUID = 6563596191450032613L;
@ApiModelProperty(
name = "deviceType",
value = "Device type (i.e: android, ios, windows)",
required = true)
private String deviceType;
@ApiModelProperty(
name = "enrollmentType",
value = "Enrollment type (i.e: BYOD, COPE, COSU)",
required = true)
private List<String> enrollmentType;
public String getDeviceType() {
return deviceType;
}
public void setDeviceType(String deviceType) {
this.deviceType = deviceType;
}
public List<String> getEnrollmentType() {
return enrollmentType;
}
public void setEnrollmentType(List<String> enrollmentType) {
this.enrollmentType = enrollmentType;
}
}

@ -0,0 +1,36 @@
package org.wso2.carbon.device.mgt.common.invitation.mgt;
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 = "EnrollmentDetails", propOrder = {
"enrollmentType",
"enrollmentSteps"
})
public class EnrollmentDetails {
@XmlElement(name = "EnrollmentType")
private String enrollmentType;
@XmlElement(name = "EnrollmentSteps")
private String enrollmentSteps;
public String getEnrollmentType() {
return enrollmentType;
}
public void setEnrollmentType(String enrollmentType) {
this.enrollmentType = enrollmentType;
}
public String getEnrollmentSteps() {
return enrollmentSteps;
}
public void setEnrollmentSteps(String enrollmentSteps) {
this.enrollmentSteps = enrollmentSteps;
}
}

@ -18,5 +18,5 @@
package org.wso2.carbon.device.mgt.common.otp.mgt;
public enum OTPEmailTypes {
USER_VERIFY, ENROLLMENT
USER_VERIFY, DEVICE_ENROLLMENT
}

@ -38,6 +38,7 @@ import org.wso2.carbon.device.mgt.common.*;
import org.wso2.carbon.device.mgt.common.app.mgt.ApplicationManager;
import org.wso2.carbon.device.mgt.common.exceptions.DeviceManagementException;
import org.wso2.carbon.device.mgt.common.general.GeneralConfig;
import org.wso2.carbon.device.mgt.common.invitation.mgt.DeviceEnrollmentInvitationDetails;
import org.wso2.carbon.device.mgt.common.policy.mgt.PolicyMonitoringManager;
import org.wso2.carbon.device.mgt.common.pull.notification.PullNotificationSubscriber;
import org.wso2.carbon.device.mgt.common.push.notification.PushNotificationConfig;
@ -77,4 +78,6 @@ public interface DeviceManagementService {
DeviceTypePlatformDetails getDeviceTypePlatformDetails();
DeviceEnrollmentInvitationDetails getDeviceEnrollmentInvitationDetails();
}

@ -20,6 +20,7 @@ package org.wso2.carbon.device.mgt.common.spi;
import org.wso2.carbon.device.mgt.common.exceptions.BadRequestException;
import org.wso2.carbon.device.mgt.common.exceptions.DeviceManagementException;
import org.wso2.carbon.device.mgt.common.exceptions.OTPManagementException;
import org.wso2.carbon.device.mgt.common.invitation.mgt.DeviceEnrollmentInvitation;
import org.wso2.carbon.device.mgt.common.otp.mgt.dto.OneTimePinDTO;
import org.wso2.carbon.device.mgt.common.otp.mgt.wrapper.OTPWrapper;
@ -48,4 +49,12 @@ public interface OTPManagementService {
* @throws OTPManagementException If error occurred while invalidating the OTP
*/
void invalidateOTP(String oneTimeToken) throws OTPManagementException;
/**
* Create OTP token and send device enrollment invitation
* @param deviceEnrollmentInvitation object which contains device enrollment invitation related details
* @throws OTPManagementException if error occurred while creating OTP token &/ sending mail
*/
void sendDeviceEnrollmentInvitationMail(DeviceEnrollmentInvitation deviceEnrollmentInvitation)
throws OTPManagementException;
}

@ -143,6 +143,9 @@ public final class DeviceManagementConstants {
public static final String DEFAULT_DEVICE_USER = "Internal/devicemgt-user";
public static final String DEFAULT_DEVICE_ADMIN = "Internal/devicemgt-admin";
public static final String CLAIM_EMAIL_ADDRESS = "http://wso2.org/claims/emailaddress";
public static final String CLAIM_FIRST_NAME = "http://wso2.org/claims/givenname";
// Permissions that are given for a normal device user.
public static final Permission[] PERMISSIONS_FOR_DEVICE_USER = {
new Permission("/permission/admin/Login", "ui.execute"),

@ -21,6 +21,7 @@ import org.apache.commons.lang.StringUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.wso2.carbon.base.MultitenantConstants;
import org.wso2.carbon.context.CarbonContext;
import org.wso2.carbon.device.mgt.common.configuration.mgt.ConfigurationManagementException;
import org.wso2.carbon.device.mgt.common.exceptions.BadRequestException;
import org.wso2.carbon.device.mgt.common.exceptions.DBConnectionException;
@ -28,7 +29,11 @@ import org.wso2.carbon.device.mgt.common.exceptions.DeviceManagementException;
import org.wso2.carbon.device.mgt.common.exceptions.OTPManagementException;
import org.wso2.carbon.device.mgt.common.exceptions.TransactionManagementException;
import org.wso2.carbon.device.mgt.common.exceptions.UnAuthorizedException;
import org.wso2.carbon.device.mgt.common.invitation.mgt.DeviceEnrollmentInvitation;
import org.wso2.carbon.device.mgt.common.invitation.mgt.DeviceEnrollmentInvitationDetails;
import org.wso2.carbon.device.mgt.common.invitation.mgt.DeviceEnrollmentType;
import org.wso2.carbon.device.mgt.common.metadata.mgt.Metadata;
import org.wso2.carbon.device.mgt.common.otp.mgt.OTPEmailTypes;
import org.wso2.carbon.device.mgt.common.otp.mgt.dto.OneTimePinDTO;
import org.wso2.carbon.device.mgt.common.spi.OTPManagementService;
import org.wso2.carbon.device.mgt.core.DeviceManagementConstants;
@ -41,9 +46,12 @@ import org.wso2.carbon.device.mgt.common.otp.mgt.wrapper.OTPWrapper;
import org.wso2.carbon.device.mgt.core.otp.mgt.dao.OTPManagementDAOFactory;
import org.wso2.carbon.device.mgt.core.otp.mgt.exception.OTPManagementDAOException;
import org.wso2.carbon.device.mgt.core.otp.mgt.util.ConnectionManagerUtil;
import org.wso2.carbon.device.mgt.core.service.DeviceManagementProviderService;
import org.wso2.carbon.device.mgt.core.service.EmailMetaInfo;
import org.apache.commons.validator.routines.EmailValidator;
import org.wso2.carbon.device.mgt.core.util.DeviceManagerUtil;
import org.wso2.carbon.user.api.Tenant;
import org.wso2.carbon.user.api.UserStoreException;
import static org.wso2.carbon.device.mgt.common.DeviceManagementConstants.OTPProperties;
@ -82,7 +90,7 @@ public class OTPManagementServiceImpl implements OTPManagementService {
Properties props = new Properties();
props.setProperty("first-name", tenant.getAdminFirstName());
props.setProperty("otp-token", oneTimePinDTO.getOtpToken());
sendMail(props, tenant.getEmail());
sendMail(props, tenant.getEmail(), DeviceManagementConstants.EmailAttributes.USER_VERIFY_TEMPLATE);
ConnectionManagerUtil.commitDBTransaction();
} catch (TransactionManagementException e) {
String msg = "Error occurred while disabling AutoCommit.";
@ -135,7 +143,7 @@ public class OTPManagementServiceImpl implements OTPManagementService {
Properties props = new Properties();
props.setProperty("first-name", tenant.getAdminFirstName());
props.setProperty("otp-token", renewedOTP);
sendMail(props, oneTimePinDTO.getEmail());
sendMail(props, oneTimePinDTO.getEmail(), DeviceManagementConstants.EmailAttributes.USER_VERIFY_TEMPLATE);
return null;
}
return oneTimePinDTO;
@ -171,6 +179,48 @@ public class OTPManagementServiceImpl implements OTPManagementService {
}
@Override
public void sendDeviceEnrollmentInvitationMail(DeviceEnrollmentInvitation deviceEnrollmentInvitation)
throws OTPManagementException {
DeviceManagementProviderService dms = DeviceManagementDataHolder.getInstance().getDeviceManagementProvider();
StringBuilder enrollmentSteps = new StringBuilder();
DeviceEnrollmentInvitationDetails deviceEnrollmentInvitationDetails;
for (DeviceEnrollmentType deviceEnrollmentType : deviceEnrollmentInvitation.getDeviceEnrollmentTypes()) {
deviceEnrollmentInvitationDetails = dms.getDeviceEnrollmentInvitationDetails(
deviceEnrollmentType.getDeviceType());
if (deviceEnrollmentInvitationDetails != null &&
deviceEnrollmentInvitationDetails.getEnrollmentDetails() != null) {
for (String enrollmentType : deviceEnrollmentType.getEnrollmentType()) {
deviceEnrollmentInvitationDetails.getEnrollmentDetails().stream()
.filter(details -> enrollmentType.equals(details.getEnrollmentType())).findFirst()
.ifPresent(details -> enrollmentSteps.append(details.getEnrollmentSteps()));
}
}
}
int tenantId = CarbonContext.getThreadLocalCarbonContext().getTenantId();
OneTimePinDTO oneTimePinDTO;
Properties props = new Properties();
props.setProperty("enrollment-steps", enrollmentSteps.toString());
try {
for (String username : deviceEnrollmentInvitation.getUsernames()) {
String emailAddress = DeviceManagerUtil.getUserClaimValue(
username, DeviceManagementConstants.User.CLAIM_EMAIL_ADDRESS);
oneTimePinDTO = createOneTimePin(emailAddress, OTPEmailTypes.DEVICE_ENROLLMENT.toString(), username,
null, tenantId);
props.setProperty("first-name", DeviceManagerUtil.
getUserClaimValue(username, DeviceManagementConstants.User.CLAIM_FIRST_NAME));
props.setProperty("username", username);
props.setProperty("otp-token", oneTimePinDTO.getOtpToken());
sendMail(props, emailAddress, DeviceManagementConstants.EmailAttributes.USER_ENROLLMENT_TEMPLATE);
}
} catch (UserStoreException e) {
String msg = "Error occurred while getting claim values to invite user";
log.error(msg, e);
throw new OTPManagementException(msg, e);
}
}
/**
* Create One Time Token
* @param email email
@ -341,15 +391,16 @@ public class OTPManagementServiceImpl implements OTPManagementService {
* If OTP expired, resend the user verifying mail with renewed OTP
* @param props Mail body properties
* @param mailAddress Mail Address of the User
* @param template Mail template to be used
* @throws OTPManagementException if error occurred while resend the user verifying mail
*/
private void sendMail(Properties props, String mailAddress) throws OTPManagementException {
private void sendMail(Properties props, String mailAddress, String template) throws OTPManagementException {
try {
EmailMetaInfo metaInfo = new EmailMetaInfo(mailAddress, props);
DeviceManagementDataHolder.getInstance().getDeviceManagementProvider()
.sendEnrolmentInvitation(DeviceManagementConstants.EmailAttributes.USER_VERIFY_TEMPLATE, metaInfo);
.sendEnrolmentInvitation(template, metaInfo);
} catch (DeviceManagementException e) {
String msg = "Error occurred while inviting user to enrol their device";
String msg = "Error occurred while sending email using email template '" + template + "'.";
log.error(msg, e);
throw new OTPManagementException(msg, e);
} catch (ConfigurationManagementException e) {

@ -14,26 +14,9 @@
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
/*
* Copyright (c) 2019, Entgra (pvt) Ltd. (http://entgra.io) All Rights Reserved.
*
* Entgra (pvt) Ltd. 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.
*/
/*
* Copyright (c) 2020, Entgra (pvt) Ltd. (http://entgra.io) All Rights Reserved.
* Copyright (c) 2019, Entgra (pvt) Ltd. (http://entgra.io) All Rights Reserved.
*
* Entgra (pvt) Ltd. licenses this file to you under the Apache License,
* Version 2.0 (the "License"); you may not use this file except
@ -76,6 +59,7 @@ import org.wso2.carbon.device.mgt.common.configuration.mgt.ConfigurationManageme
import org.wso2.carbon.device.mgt.common.configuration.mgt.DeviceConfiguration;
import org.wso2.carbon.device.mgt.common.configuration.mgt.PlatformConfiguration;
import org.wso2.carbon.device.mgt.common.device.details.DeviceData;
import org.wso2.carbon.device.mgt.common.invitation.mgt.DeviceEnrollmentInvitationDetails;
import org.wso2.carbon.device.mgt.common.license.mgt.License;
import org.wso2.carbon.device.mgt.common.operation.mgt.Activity;
import org.wso2.carbon.device.mgt.common.operation.mgt.Operation;
@ -926,4 +910,12 @@ public interface DeviceManagementProviderService {
*/
List<Device> getDeviceByIdList(List<String> deviceIdentifiers)
throws DeviceManagementException;
/**
* Retrieve device enrollment details to be sent device enrollment invitation.
* This has the relevant enrollment steps of each enrollment types.
* @param deviceType Device type of the required device enrollment details
* @return enrollment steps of each enrollment types which are provided in the device type xml file
*/
DeviceEnrollmentInvitationDetails getDeviceEnrollmentInvitationDetails(String deviceType);
}

@ -14,6 +14,23 @@
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*
*
* Copyright (c) 2020, Entgra (Pvt) Ltd. (http://www.entgra.io) All Rights Reserved.
*
* Entgra (Pvt) Ltd. 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.core.service;
@ -74,6 +91,7 @@ import org.wso2.carbon.device.mgt.common.group.mgt.DeviceGroup;
import org.wso2.carbon.device.mgt.common.group.mgt.DeviceGroupConstants;
import org.wso2.carbon.device.mgt.common.group.mgt.GroupAlreadyExistException;
import org.wso2.carbon.device.mgt.common.group.mgt.GroupManagementException;
import org.wso2.carbon.device.mgt.common.invitation.mgt.DeviceEnrollmentInvitationDetails;
import org.wso2.carbon.device.mgt.common.license.mgt.License;
import org.wso2.carbon.device.mgt.common.license.mgt.LicenseManagementException;
import org.wso2.carbon.device.mgt.common.operation.mgt.Activity;
@ -4187,4 +4205,11 @@ public class DeviceManagementProviderServiceImpl implements DeviceManagementProv
DeviceManagementDAOFactory.closeConnection();
}
}
@Override
public DeviceEnrollmentInvitationDetails getDeviceEnrollmentInvitationDetails(String deviceType) {
int tenantId = PrivilegedCarbonContext.getThreadLocalCarbonContext().getTenantId();
DeviceManagementService dms = pluginRepository.getDeviceManagementService(deviceType, tenantId);
return dms.getDeviceEnrollmentInvitationDetails();
}
}

@ -14,6 +14,23 @@
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*
*
* Copyright (c) 2020, Entgra (Pvt) Ltd. (http://www.entgra.io) All Rights Reserved.
*
* Entgra (Pvt) Ltd. 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.core.util;
@ -79,6 +96,7 @@ import org.wso2.carbon.identity.jwt.client.extension.service.JWTClientManagerSer
import org.wso2.carbon.user.api.TenantManager;
import org.wso2.carbon.user.api.UserRealm;
import org.wso2.carbon.user.api.UserStoreException;
import org.wso2.carbon.user.api.UserStoreManager;
import org.wso2.carbon.utils.CarbonUtils;
import org.wso2.carbon.utils.ConfigurationContextService;
import org.wso2.carbon.utils.NetworkUtils;
@ -1047,4 +1065,17 @@ public final class DeviceManagerUtil {
}
return roleList;
}
/**
* Retrieve the value of the user property from the user profile
* @param username of the user
* @param claimUri name of the claim
* @return value for the claim uri of user
* @throws UserStoreException when there is error in retrieving the user store manager
*/
public static String getUserClaimValue(String username, String claimUri) throws UserStoreException {
UserStoreManager userStoreManager = CarbonContext.getThreadLocalCarbonContext().getUserRealm()
.getUserStoreManager();
return userStoreManager.getUserClaimValue(username, claimUri, null);
}
}

@ -37,6 +37,7 @@ import org.wso2.carbon.device.mgt.common.*;
import org.wso2.carbon.device.mgt.common.app.mgt.ApplicationManager;
import org.wso2.carbon.device.mgt.common.exceptions.DeviceManagementException;
import org.wso2.carbon.device.mgt.common.general.GeneralConfig;
import org.wso2.carbon.device.mgt.common.invitation.mgt.DeviceEnrollmentInvitationDetails;
import org.wso2.carbon.device.mgt.common.policy.mgt.PolicyMonitoringManager;
import org.wso2.carbon.device.mgt.common.pull.notification.PullNotificationSubscriber;
import org.wso2.carbon.device.mgt.common.push.notification.PushNotificationConfig;
@ -142,4 +143,9 @@ public class TestDeviceManagementService implements DeviceManagementService {
public DeviceTypePlatformDetails getDeviceTypePlatformDetails() {
return null;
}
@Override
public DeviceEnrollmentInvitationDetails getDeviceEnrollmentInvitationDetails() {
return null;
}
}

@ -48,6 +48,7 @@ import org.wso2.carbon.device.mgt.common.app.mgt.ApplicationManager;
import org.wso2.carbon.device.mgt.common.configuration.mgt.ConfigurationEntry;
import org.wso2.carbon.device.mgt.common.configuration.mgt.PlatformConfiguration;
import org.wso2.carbon.device.mgt.common.general.GeneralConfig;
import org.wso2.carbon.device.mgt.common.invitation.mgt.DeviceEnrollmentInvitationDetails;
import org.wso2.carbon.device.mgt.common.policy.mgt.PolicyMonitoringManager;
import org.wso2.carbon.device.mgt.common.pull.notification.PullNotificationSubscriber;
import org.wso2.carbon.device.mgt.common.push.notification.PushNotificationConfig;
@ -92,6 +93,7 @@ public class DeviceTypeManagerService implements DeviceManagementService {
private PullNotificationSubscriber pullNotificationSubscriber;
private final DeviceStatusTaskPluginConfig deviceStatusTaskPluginConfig;
private DeviceTypePlatformDetails deviceTypePlatformDetails;
private DeviceEnrollmentInvitationDetails deviceEnrollmentInvitationDetails;
private GeneralConfig generalConfig;
private boolean isRegistryBasedConfigs = false;
private boolean isScheduled = false;
@ -116,6 +118,8 @@ public class DeviceTypeManagerService implements DeviceManagementService {
this.setPolicyMonitoringManager(deviceTypeConfiguration.getPolicyMonitoring());
this.setPullNotificationSubscriber(deviceTypeConfiguration.getPullNotificationSubscriberConfig());
this.setGeneralConfig(deviceTypeConfiguration);
this.deviceEnrollmentInvitationDetails = new DeviceEnrollmentInvitationDetails();
this.setDeviceEnrollmentInvitationDetails(deviceTypeConfiguration);
}
@Override
@ -259,6 +263,11 @@ public class DeviceTypeManagerService implements DeviceManagementService {
return generalConfig;
}
@Override
public DeviceEnrollmentInvitationDetails getDeviceEnrollmentInvitationDetails() {
return deviceEnrollmentInvitationDetails;
}
private void setProvisioningConfig(String tenantDomain, DeviceTypeConfiguration deviceTypeConfiguration) {
if (deviceTypeConfiguration.getProvisioningConfig() != null) {
boolean sharedWithAllTenants = deviceTypeConfiguration.getProvisioningConfig().isSharedWithAllTenants();
@ -354,4 +363,13 @@ public class DeviceTypeManagerService implements DeviceManagementService {
deviceTypePlatformDetails.setDeviceTypePlatformVersion(deviceTypeVersions.getDeviceTypePlatformVersion());
}
}
public void setDeviceEnrollmentInvitationDetails(DeviceTypeConfiguration deviceTypeConfiguration) {
DeviceEnrollmentInvitationDetails deviceEnrollmentInvitationDetailsFromConfig = deviceTypeConfiguration
.getDeviceEnrollmentInvitationDetails();
if (deviceEnrollmentInvitationDetailsFromConfig != null) {
deviceEnrollmentInvitationDetails.setEnrollmentDetails(
deviceEnrollmentInvitationDetailsFromConfig.getEnrollmentDetails());
}
}
}

@ -34,6 +34,7 @@
*/
package org.wso2.carbon.device.mgt.extensions.device.type.template.config;
import org.wso2.carbon.device.mgt.common.invitation.mgt.DeviceEnrollmentInvitationDetails;
import org.wso2.carbon.device.mgt.common.type.mgt.DeviceTypePlatformDetails;
import javax.xml.bind.annotation.XmlElement;
@ -107,6 +108,8 @@ public class DeviceTypeConfiguration {
protected List<String> operations;
@XmlElement(name = "DeviceTypePlatformDetails", required = true)
protected DeviceTypePlatformDetails deviceTypePlatformDetails;
@XmlElement(name = "DeviceEnrollmentInvitationDetails", required = true)
protected DeviceEnrollmentInvitationDetails deviceEnrollmentInvitationDetails;
public DeviceTypePlatformDetails getDeviceTypePlatformDetails() {
return deviceTypePlatformDetails;
@ -414,4 +417,21 @@ public class DeviceTypeConfiguration {
public void setStartupOperations(List<String> startupOperations) {
this.startupOperations = startupOperations;
}
/**
* Gets the value of device enrollment invitation details which has enrollment steps of enrollment types
* @return device enrollment invitation details
*/
public DeviceEnrollmentInvitationDetails getDeviceEnrollmentInvitationDetails() {
return deviceEnrollmentInvitationDetails;
}
/**
* Sets the value of device enrollment invitation details from the relevant device type xml file
* @param deviceEnrollmentInvitationDetails {@link DeviceEnrollmentInvitationDetails} object
*/
public void setDeviceEnrollmentInvitationDetails(
DeviceEnrollmentInvitationDetails deviceEnrollmentInvitationDetails) {
this.deviceEnrollmentInvitationDetails = deviceEnrollmentInvitationDetails;
}
}

@ -44,6 +44,7 @@ import org.wso2.carbon.device.mgt.common.ProvisioningConfig;
import org.wso2.carbon.device.mgt.common.StartupOperationConfig;
import org.wso2.carbon.device.mgt.common.app.mgt.ApplicationManager;
import org.wso2.carbon.device.mgt.common.general.GeneralConfig;
import org.wso2.carbon.device.mgt.common.invitation.mgt.DeviceEnrollmentInvitationDetails;
import org.wso2.carbon.device.mgt.common.policy.mgt.PolicyMonitoringManager;
import org.wso2.carbon.device.mgt.common.pull.notification.PullNotificationSubscriber;
import org.wso2.carbon.device.mgt.common.push.notification.PushNotificationConfig;
@ -131,4 +132,9 @@ public class TypeXDeviceManagementService implements DeviceManagementService {
public DeviceTypePlatformDetails getDeviceTypePlatformDetails() {
return null;
}
@Override
public DeviceEnrollmentInvitationDetails getDeviceEnrollmentInvitationDetails() {
return null;
}
}

@ -14,6 +14,22 @@
KIND, either express or implied. See the License for the
specific language governing permissions and limitations
under the License.
Copyright (c) 2019, Entgra (Pvt) Ltd. (http://www.entgra.io) All Rights Reserved.
Entgra (Pvt) Ltd. 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.
*#
<EmailConfig>
<Subject>You have been invited to enroll your device in Entgra IoT</Subject>
@ -206,7 +222,13 @@ TkSuQmCC"
</p>
<p style="font-size: 1em; font-family: Arial, Helvetica; line-height: 170%; color: #666666; margin: 5px 0px;">
You have been invited to enrol your device in Entgra IoT Server.
Click <a href="$base-url-https/devicemgt/device/enroll">here</a> to begin device enrolment.</p>
Click <a href="$base-url-https/endpoint-mgt/device/enroll?otp=$otp-token">here</a> to begin device enrolment.</p>
<p style="font-length: 1em; font-family: Arial, Helvetica; line-height: 170%; color: #666666; margin: 5px 0px;">
Enrollment Steps are as below,
</p>
$enrollment-steps
<p style="font-length: 1em; font-family: Arial, Helvetica; line-height: 170%; color: #666666; margin: 5px 0px;">
Should you need assistance, please contact your administrator.

Loading…
Cancel
Save