Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

4.8.0 content security #52

Open
wants to merge 23 commits into
base: cbrelease-4.8.0
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
18c93ef
enrol and unenroll api latest changes (#43)
Manas-tarento May 29, 2023
0150720
fixed
Manas-tarento May 30, 2023
d9a65fc
fixed
Manas-tarento Jun 5, 2023
64f072f
Merge pull request #46 from Manas-tarento/4.8.0-contentSecurity
Haritest Jun 5, 2023
f309924
fixed
Manas-tarento Jun 5, 2023
07842e3
Merge pull request #47 from Manas-tarento/4.8.0-contentSecurity
Haritest Jun 5, 2023
8454b44
fixed
Manas-tarento Jun 5, 2023
0a84b11
null check
Manas-tarento Jun 6, 2023
ec9cece
Merge pull request #48 from Manas-tarento/4.8.0-contentSecurity
Haritest Jun 6, 2023
ae32ccb
null check
Manas-tarento Jun 6, 2023
50e4b38
Merge pull request #49 from Manas-tarento/4.8.0-contentSecurity
Haritest Jun 6, 2023
cc9f6ca
added logger
Manas-tarento Jun 6, 2023
55701d1
Merge pull request #50 from Manas-tarento/4.8.0-contentSecurity
Haritest Jun 6, 2023
0957a2c
list enrol api fix (#51)
Manas-tarento Jun 6, 2023
feeaf84
Updated debug log
karthik-tarento Jun 6, 2023
55df888
Using different approach for reading headers
karthik-tarento Jun 6, 2023
cf3b24e
Updated debug logs
karthik-tarento Jun 6, 2023
60a5639
Fixed typo in variable name
karthik-tarento Jun 7, 2023
ce4dce7
Fixes for internal content search
karthik-tarento Jun 7, 2023
a07cbe2
Added headers properly
karthik-tarento Jun 7, 2023
b396718
Fixes for NPE
karthik-tarento Jun 7, 2023
b6b89b3
Removed unnecessary debug logs
karthik-tarento Jun 7, 2023
f3d055e
Merge branch '4.8.0-contentSecurityV2' into 4.8.0-contentSecurity
karthik-tarento Jun 8, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -39,9 +39,15 @@ public class ContentSearchUtil {
contentSearchURL = baseUrl + searchPath;
}

private static Map<String, String> getUpdatedHeaders(Map<String, String> headers) {
if (headers == null) {
headers = new HashMap<>();
private static Map<String, String> getUpdatedHeaders(Map<String, String> allHeaders) {
Map<String, String> headers = new HashMap<String, String>();
if (allHeaders != null) {
if (allHeaders.containsKey(JsonKey.X_AUTHENTICATED_USER_TOKEN)) {
headers.put(JsonKey.X_AUTHENTICATED_USER_TOKEN, allHeaders.get(JsonKey.X_AUTHENTICATED_USER_TOKEN));
}
if (allHeaders.containsKey(JsonKey.X_AUTH_USER_ORG_ID)) {
headers.put(JsonKey.X_AUTH_USER_ORG_ID, allHeaders.get(JsonKey.X_AUTH_USER_ORG_ID));
}
}
headers.put(
HttpHeaders.AUTHORIZATION, JsonKey.BEARER + System.getenv(JsonKey.SUNBIRD_AUTHORIZATION));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -197,4 +197,25 @@ public static boolean updateCollection(RequestContext requestContext, String col
}
return JsonKey.SUCCESS.equalsIgnoreCase(response);
}

public static boolean getContentRead(String courseId, Map<String, String> allHeaders) {
boolean flag = false;
try {
Map<String, String> headers = new HashMap<String, String>();
if (allHeaders.containsKey(JsonKey.X_AUTH_USER_ORG_ID)) {
headers.put(JsonKey.X_AUTH_USER_ORG_ID, allHeaders.get(JsonKey.X_AUTH_USER_ORG_ID));
}
String baseContentreadUrl = ProjectUtil.getConfigValue(JsonKey.EKSTEP_BASE_URL) + "/content/v3/read/" + courseId;
String response = HttpUtil.sendGetRequest(baseContentreadUrl, headers);
if (response != null && !response.isEmpty()) {
Map<String, Object> data = mapper.readValue(response, Map.class);
if (JsonKey.OK.equalsIgnoreCase((String) data.get(JsonKey.RESPONSE_CODE))) {
flag = true;
}
}
} catch (Exception e) {
logger.error(null, "User don't have access to this courseId " + courseId, e);
}
return flag;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -85,12 +85,17 @@ class CourseEnrolmentActor @Inject()(@Named("course-batch-notification-actor") c
validateEnrolment(batchData, enrolmentData, true)
val dataBatch: util.Map[String, AnyRef] = createBatchUserMapping(batchId, userId,batchUserData)
val data: java.util.Map[String, AnyRef] = createUserEnrolmentMap(userId, courseId, batchId, enrolmentData, request.getContext.getOrDefault(JsonKey.REQUEST_ID, "").asInstanceOf[String])
upsertEnrollment(userId, courseId, batchId, data, dataBatch, (null == enrolmentData), request.getRequestContext)
logger.info(request.getRequestContext, "CourseEnrolmentActor :: enroll :: Deleting redis for key " + getCacheKey(userId))
cacheUtil.delete(getCacheKey(userId))
sender().tell(successResponse(), self)
generateTelemetryAudit(userId, courseId, batchId, data, "enrol", JsonKey.CREATE, request.getContext)
notifyUser(userId, batchData, JsonKey.ADD)
val hasAccess = ContentUtil.getContentRead(courseId, request.getContext.getOrDefault(JsonKey.HEADER, new util.HashMap[String, String]).asInstanceOf[util.Map[String, String]])
if (hasAccess) {
upsertEnrollment(userId, courseId, batchId, data, dataBatch, (null == enrolmentData), request.getRequestContext)
logger.info(request.getRequestContext, "CourseEnrolmentActor :: enroll :: Deleting redis for key " + getCacheKey(userId))
cacheUtil.delete(getCacheKey(userId))
sender().tell(successResponse(), self)
generateTelemetryAudit(userId, courseId, batchId, data, "enrol", JsonKey.CREATE, request.getContext)
notifyUser(userId, batchData, JsonKey.ADD)
} else {
ProjectCommonException.throwClientErrorException(ResponseCode.accessDeniedToEnrolOrUnenrolCourse, courseId)
}
}

def unEnroll(request:Request): Unit = {
Expand All @@ -104,12 +109,17 @@ class CourseEnrolmentActor @Inject()(@Named("course-batch-notification-actor") c
getUpdatedStatus(enrolmentData)
validateEnrolment(batchData, enrolmentData, false)
val data: java.util.Map[String, AnyRef] = new java.util.HashMap[String, AnyRef]() {{ put(JsonKey.ACTIVE, ProjectUtil.ActiveStatus.INACTIVE.getValue.asInstanceOf[AnyRef]) }}
upsertEnrollment(userId,courseId, batchId, data,dataBatch, false, request.getRequestContext)
logger.info(request.getRequestContext, "CourseEnrolmentActor :: unEnroll :: Deleting redis for key " + getCacheKey(userId))
cacheUtil.delete(getCacheKey(userId))
sender().tell(successResponse(), self)
generateTelemetryAudit(userId, courseId, batchId, data, "unenrol", JsonKey.UPDATE, request.getContext)
notifyUser(userId, batchData, JsonKey.REMOVE)
val hasAccess = ContentUtil.getContentRead(courseId, request.getContext.getOrDefault(JsonKey.HEADER, new util.HashMap[String, String]).asInstanceOf[util.Map[String, String]])
if (hasAccess) {
upsertEnrollment(userId,courseId, batchId, data, dataBatch, false, request.getRequestContext)
logger.info(request.getRequestContext, "CourseEnrolmentActor :: unEnroll :: Deleting redis for key " + getCacheKey(userId))
cacheUtil.delete(getCacheKey(userId))
sender().tell(successResponse(), self)
generateTelemetryAudit(userId, courseId, batchId, data, "unenrol", JsonKey.UPDATE, request.getContext)
notifyUser(userId, batchData, JsonKey.REMOVE)
} else {
ProjectCommonException.throwClientErrorException(ResponseCode.accessDeniedToEnrolOrUnenrolCourse, courseId)
}
}

def list(request: Request): Unit = {
Expand All @@ -136,9 +146,9 @@ class CourseEnrolmentActor @Inject()(@Named("course-batch-notification-actor") c
new util.ArrayList[java.util.Map[String, AnyRef]]()
}

def addCourseDetails(activeEnrolments: java.util.List[java.util.Map[String, AnyRef]], courseIds: java.util.List[String] , request:Request): java.util.List[java.util.Map[String, AnyRef]] = {
val requestBody: String = prepareSearchRequest(courseIds, request)
val searchResult:java.util.Map[String, AnyRef] = ContentSearchUtil.searchContentSync(request.getRequestContext, request.getContext.getOrDefault(JsonKey.URL_QUERY_STRING,"").asInstanceOf[String], requestBody, request.get(JsonKey.HEADER).asInstanceOf[java.util.Map[String, String]])
def addCourseDetails(activeEnrolments: java.util.List[java.util.Map[String, AnyRef]], courseIds: java.util.List[String] , request:Request, flag:Boolean): java.util.List[java.util.Map[String, AnyRef]] = {
val requestBody: String = prepareSearchRequest(courseIds, request, flag)
val searchResult:java.util.Map[String, AnyRef] = ContentSearchUtil.searchContentSync(request.getRequestContext, request.getContext.getOrDefault(JsonKey.URL_QUERY_STRING,"").asInstanceOf[String], requestBody, request.getContext.getOrDefault(JsonKey.HEADER, new util.HashMap[String, String]).asInstanceOf[util.Map[String, String]])
val coursesList: java.util.List[java.util.Map[String, AnyRef]] = searchResult.getOrDefault(JsonKey.CONTENTS, new java.util.ArrayList[java.util.Map[String, AnyRef]]()).asInstanceOf[java.util.List[java.util.Map[String, AnyRef]]]
val coursesMap = {
if(CollectionUtils.isNotEmpty(coursesList)) {
Expand All @@ -158,7 +168,7 @@ class CourseEnrolmentActor @Inject()(@Named("course-batch-notification-actor") c
}).toList.asJava
}

def prepareSearchRequest(courseIds: java.util.List[String], request: Request): String = {
def prepareSearchRequest(courseIds: java.util.List[String], request: Request, flag:Boolean): String = {
val filters: java.util.Map[String, AnyRef] = new java.util.HashMap[String, AnyRef]() {{
put(JsonKey.IDENTIFIER, courseIds)
put(JsonKey.STATUS, "Live")
Expand All @@ -169,6 +179,7 @@ class CourseEnrolmentActor @Inject()(@Named("course-batch-notification-actor") c
val searchRequest:java.util.Map[String, java.util.Map[String, AnyRef]] = new java.util.HashMap[String, java.util.Map[String, AnyRef]]() {{
put(JsonKey.REQUEST, new java.util.HashMap[String, AnyRef](){{
put(JsonKey.FILTERS, filters)
put(JsonKey.SECURE_SETTINGS, flag.asInstanceOf[AnyRef])
put(JsonKey.LIMIT, courseIds.size().asInstanceOf[AnyRef])
}})
}}
Expand Down Expand Up @@ -348,9 +359,26 @@ class CourseEnrolmentActor @Inject()(@Named("course-batch-notification-actor") c
val activeEnrolments: java.util.List[java.util.Map[String, AnyRef]] = getActiveEnrollments( userId, courseIdList, request.getRequestContext)
val enrolments: java.util.List[java.util.Map[String, AnyRef]] = {
if (CollectionUtils.isNotEmpty(activeEnrolments)) {
val courseIds: java.util.List[String] = activeEnrolments.map(e => e.getOrDefault(JsonKey.COURSE_ID, "").asInstanceOf[String]).distinct.filter(id => StringUtils.isNotBlank(id)).toList.asJava
val enrolmentList: java.util.List[java.util.Map[String, AnyRef]] = addCourseDetails(activeEnrolments, courseIds, request)
val updatedEnrolmentList = updateProgressData(enrolmentList, userId, courseIds, request.getRequestContext)
val allCourseIds: java.util.List[String] = activeEnrolments.map(e => e.getOrDefault(JsonKey.COURSE_ID, "").asInstanceOf[String]).distinct.filter(id => StringUtils.isNotBlank(id)).toList.asJava
val courseIds = new java.util.ArrayList[String]()
val secureCourseIds = new java.util.ArrayList[String]()
for (courseId <- allCourseIds.asScala) {
if (courseId.endsWith("_rc")) {
secureCourseIds.add(courseId)
} else {
courseIds.add(courseId)
}
}
val allEnrolledCourses = new java.util.ArrayList[java.util.Map[String, AnyRef]]
val enrolmentList: java.util.List[java.util.Map[String, AnyRef]] = addCourseDetails(activeEnrolments, courseIds, request, false)
if (enrolmentList != null) {
allEnrolledCourses.addAll(enrolmentList)
}
val secureCourseEnrolmentList: java.util.List[java.util.Map[String, AnyRef]] = addCourseDetails(activeEnrolments, secureCourseIds, request, true)
if (secureCourseEnrolmentList != null) {
allEnrolledCourses.addAll(secureCourseEnrolmentList)
}
val updatedEnrolmentList = updateProgressData(allEnrolledCourses, userId, allCourseIds, request.getRequestContext)
addBatchDetails(updatedEnrolmentList, request)
} else new java.util.ArrayList[java.util.Map[String, AnyRef]]()
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1076,5 +1076,7 @@ public final class JsonKey {
public static final String COURSE_USER_ENROLMENTS_DB = "course_user_enrolments_db";
public static final String COURSE_BATCH_PATH = "sunbird_course_batch_path";
public static final String CURRENT_OFFSET = "currentOffSet";
public static final String SECURE_SETTINGS = "secureSettings";
public static final String X_AUTH_USER_ORG_ID = "x-authenticated-user-orgid";
private JsonKey() {}
}
Original file line number Diff line number Diff line change
Expand Up @@ -832,7 +832,7 @@ public enum ResponseCode {
cannotUpdateEventSetHavingEnrollments(
ResponseMessage.Key.CANNOT_UPDATE_EVENT_SET_HAVING_ENROLLMENTS,
ResponseMessage.Message.CANNOT_UPDATE_EVENT_SET_HAVING_ENROLLMENTS),

accessDeniedToEnrolOrUnenrolCourse(ResponseMessage.Key.USER_DOES_NOT_HAVE_ACCESS,ResponseMessage.Message.USER_DOES_NOT_HAVE_ACCESS),
OK(200),
CLIENT_ERROR(400),
SERVER_ERROR(500),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -459,6 +459,7 @@ interface Message {
String ERR_CALLING_GROUP_API = "Error while calling group api.";
String MISSING_FIXED_BATCH_ID = "Missing Fixed Batch Id.";
String CANNOT_UPDATE_EVENT_SET_HAVING_ENROLLMENTS = "Cannot update event set having enrollments.";
String USER_DOES_NOT_HAVE_ACCESS = "User doesn't have access to this Course Id";
}

interface Key {
Expand Down Expand Up @@ -846,5 +847,6 @@ interface Key {
String ERR_CALLING_GROUP_API = "ERR_CALLING_GROUOP_API";
String MISSING_FIXED_BATCH_ID = "MISSING_FIXED_BATCH_ID";
String CANNOT_UPDATE_EVENT_SET_HAVING_ENROLLMENTS = "CANNOT_UPDATE_EVENT_SET_HAVING_ENROLLMENTS";
String USER_DOES_NOT_HAVE_ACCESS = "USER_DOES_NOT_HAVE_ACCESS";
}
}