Name

sn_smd.SMSecurityManager

Description

No description available

Script

var SMSecurityManager = Class.create();

SMSecurityManager.CREATE = 'create';
SMSecurityManager.READ = 'read';
SMSecurityManager.WRITE = 'write';
SMSecurityManager.DELETE = 'delete';
SMSecurityManager.EXECUTE = 'execute';
SMSecurityManager.ADMINISTER_SECURITY = 'administer_security';

SMSecurityManager.PROFILE_MANAGER = 'profile';
SMSecurityManager.MEMBERSHIP_MANAGER = 'manage_membership';	
SMSecurityManager.PERMISSION_CHECKER = 'check_permission';
SMSecurityManager.OWNER = 'Owner';
SMSecurityManager.ADMIN = 'Security Administrator';
SMSecurityManager.EDITOR = 'Editor';
SMSecurityManager.VIEWER = 'Viewer';
SMSecurityManager.USER = 'USER';
SMSecurityManager.GROUP = 'GROUP';

SMSecurityManager.SERVICE_MODEL_CTX = 'service_model';
SMSecurityManager.SERVICE_LAYER_CTX = 'service_layer';
SMSecurityManager.SERVICE_ENVIRONMENT_CTX = 'service_environment';
SMSecurityManager.ENVIRONMENT_TEMPLATE_CTX = 'environment_template';
SMSecurityManager.ENVIRONMENT_CTX = 'environment'; 
SMSecurityManager.DEPLOYMENT_CTX = 'deployment';
SMSecurityManager.PACKAGE_TEMPLATE_CTX = 'package_template';
SMSecurityManager.PACKAGE_CTX = 'package';

SMSecurityManager.allOperations = [SMSecurityManager.CREATE, 
  							   SMSecurityManager.READ, 
  							   SMSecurityManager.WRITE, 
  							   SMSecurityManager.DELETE, 
  							   SMSecurityManager.EXECUTE, 
  							   SMSecurityManager.ADMINISTER_SECURITY
  							  ];

SMSecurityManager.isValidOperation = function(operation) {
  return SMSecurityManager.allOperations.indexOf(operation) > -1;
};

SMSecurityManager.prototype = {
  securityContext: null, //object from service model api
  contextDefinition: null, //object from service model api
  context: null,
  defaultUser: null,

  initialize: function(context, objectId) {
  	this.defaultUser = gs.getUserName();
  	if(this.defaultUser == 'system') {
  		this.defaultUser = 'admin';
  	}
  	
  	if(gs.nil(objectId)) {
  		//most of the operations require explicit setSecurityContextForOperation call
  		return;
  	}
  	this.setSecurityContextForOperation(context, objectId);
  },
  
  getSecurityContextForOperation: function(context, objectId) {
  	if(gs.nil(this.securityContext)) {
  		this.setSecurityContextForOperation(context, objectId);
  	}
  	return this.securityContext;
  },
  
  setSecurityContextForOperation: function(context, objectId) {
  	this.context = context;
  	this.contextDefinition = this.getContextDefinition();
  	
  	if(context === SMSecurityManager.SERVICE_MODEL_CTX) {
  		/* eslint-disable no-undef */  
  		this.securityContext = sn_svcmod.ServiceContainerFactory.load(objectId);
  		/* eslint-enable no-undef */ 
  		
  	} else if(this._isLayerContext(context)){
  		this.securityContext = SMUtils.loadLayer(objectId);	
  		
  	} else if(context === SMSecurityManaget.SERVICE_ENVIRONMENT_CTX) {
  		/* eslint-disable no-undef */  
  		this.securityContext = sn_svcmod.ServiceContainerFactory.loadEnvironment(objectId);
  		/* eslint-enable no-undef */
  		
  	} else {
  		throw 'Undefined security context defintion '+ context;
  	}
  },
  
  _isLayerContext: function(context) {
  	return (context === SMSecurityManager.ENVIRONMENT_TEMPLATE_CTX
  		   || context === SMSecurityManager.ENVIRONMENT_CTX
  		   || context === SMSecurityManager.DEPLOYMENT_CTX
  		   || context === SMSecurityManager.PACKAGE_TEMPLATE_CTX
  		   || context === SMSecurityManager.PACKAGE_CTX
  		   || context === SMSecurityManager.SERVICE_LAYER_CTX);
  },
  
  getLayerContextId: function(layer) {
  	switch(layer.getKind()) {
  		case SMConstants.SVC_LAYER_KIND_SERVICE_DEF:
  			if(layer.getKindIdentifier() == SMConstants.SVC_KIND_IDENTIFIER_ENV_TMPL)
  				return SMSecurityManager.ENVIRONMENT_TEMPLATE_CTX;
  			else if(layer.getKindIdentifier() == SMConstants.SVC_KIND_IDENTIFIER_ENV_INST) 
  				return SMSecurityManager.ENVIRONMENT_CTX;
  			else
  				return SMSecurityManager.SERVICE_LAYER_CTX;
  		case SMConstants.SVC_LAYER_KIND_SERVICE_STATE:
  			return SMSecurityManager.DEPLOYMENT_CTX;
  		case SMConstants.SVC_LAYER_KIND_PACKAGE_DEF:
  			return SMSecurityManager.PACKAGE_TEMPLATE_CTX;
  		case SMConstants.SVC_LAYER_KIND_PACKAGE_STATE:
  			return SMSecurityManager.PACKAGE_CTX;
  	}
  },
  
  /**
  * returns an object with all the permissions on object for a user specified by a userName;
  * if userName is null, the current user will be used to check the permissions.
  */
  getAllPermissions: function(context, objectId, userName) {
  	var allowedOperations = {};
  	if (gs.nil(context) || gs.nil(objectId)) {
  		gs.info('Security Permission check error : invalid parameters');
  		return allowedOperations;
  	}
  	
  	this.setSecurityContextForOperation(context, objectId);		
  	try {
  		var ops =  SMSecurityManager.allOperations;
  		for(var i = 0; i <ops.length; i++) {
  			//params.user is optional
  			if(this.checkPermission(context, objectId, ops[i], userName)) {
  				allowedOperations[ops[i]] = true;
  			}
  		}
  	} catch(error) {
  		return {};
  	}
  	return allowedOperations;
  },
  
  hasAnyPermission: function(context, objectId, userName) {
  	for(var i = 0; i < SMSecurityManager.allOperations.length; i++) {
  		if(this.checkPermission(context, objectId, SMSecurityManager.allOperations[i], userName)) {
  			return true;
  		}
  	}
  	return false;
  },
  
  hasCreatePermission: function(context, objectId, userName) {	
  	return this.checkPermission(context, objectId, "create", userName);

  },
  
  hasReadPermission: function(context, objectId, userName) {	
  	return this.checkPermission(context, objectId, "read", userName);

  },
  
  hasWritePermission: function(context, objectId, userName) {	
  	return this.checkPermission(context, objectId, "write", userName);

  },
  
  hasDeletePermission: function(context, objectId, userName) {	
  	return this.checkPermission(context, objectId, "delete", userName);

  },
  
  hasAdministerSecurityPermission: function(context, objectId, userName) {	
  	return this.checkPermission(context, objectId, "administer_security", userName);

  },
  
  checkPermission: function(context, objectId, operation, userName) {

  	if(gs.nil(context) || gs.nil(objectId) || gs.nil(operation)) {
  		throw 'Context, object id, and operation is required for operation _checkPermission';
  	}
  	
  	if(!SMSecurityManager.isValidOperation(operation)) {
  		throw 'Unsupported operation '+operation;
  	}
  	
  	this.setSecurityContextForOperation(context, objectId);
  	
  	var permission =  this.securityContext.checkPermission(this.contextDefinition, operation, userName || '');
  	return this._booleanizePermission(permission);
  },
  
  _booleanizePermission: function(permission) {
  	if(permission == 'GRANT' || permission == 'INHERIT_GRANT') {
  		return true;
  	}
  	return false;
  },
  
  /**
  * @Deprecated - use addProfileMembership method instead
  * This method is intended to associate an user with a profile.  
  */
  setProfileMembership: function(ctxObject, profileName, userName, type) {
  	var user = userName || this.defaultUser;
  	var memberType = this._getMemberType(type);
  	if(memberType == SMSecurityManager.USER && gs.nil(this._getUser('sys_id', user)) && gs.nil(this._getUser('user_name', user))) {
  		if(gs.hasRole("maint")) {
  			return;
  		}
  		throw 'Invalid user to set profile membership for';	
  	}
  	
  	var profile = ctxObject.getPersona(profileName);
  	var membership = ctxObject.getMembership(profile);
  	var memberAction = membership.getAction(memberType, user);	
  	if(gs.nil(memberAction)) {
  		membership.createAction(memberType, user);
  	} else {
  		memberAction.changeAction('GRANT');
  	}	
  	
  	var sraUserRole = '7d6071c0cb312200ee62d796634c9ca3';
  	new global.ServiceModelRoleAdder().addOrRemoveRole(user, memberType, sraUserRole, 'add');
  },
  
  denyProfileMembership: function(ctxObject, profileName, userName, type) { 
  	var profile = ctxObject.getPersona(profileName);
  	var membership = ctxObject.getMembership(profile);		
  	var memberAction = membership.getAction(this._getMemberType(type), userName);
  	memberAction.changeAction('DENY'); 
  },
  
  _getMemberType: function(type) {
  	var memberType = SMSecurityManager.USER;
  	if(!gs.nil(type)) {
  		memberType = type.toUpperCase();
  	}
  	return memberType;
  },
  
  allProfiles: function() {
  	this._checkContext();
  	var availableProfiles = [];
  	var profiles = this.securityContext.availablePersonas();
  	for(var i = 0; i < profiles.length; i++) {
  		var profile = profiles[i];
  		var profileToOpsRoot = profile.getRootMapping();
  		var parentCtxs = this._findParentContextDefinitionChain(this.context);
  		var profileToOps = profileToOpsRoot;
  		for(var j = 0; j < parentCtxs.length; j++) {
  			profileToOps = profileToOps.getChild(parentCtxs[j]);
  		}					
  		profileToOps = profileToOps.getChild(this.context); 			
  		
  		var obj = {};
  		obj.profile = profile;
  		obj.operations = {};
  		//you cannot create object of current context as you are already inside it so passing false
  		this._getOperationsForProfileAndItsChildren(profileToOps, obj.operations, false);
  		if (obj.operations[this.context] && obj.operations[this.context].length > 0)
  			availableProfiles.push(obj);				
  	}
  	return this._profileDTOs(availableProfiles);
  },
  
  _getOperationsForProfileAndItsChildren: function(profileToOps, operations, hasParentCreateOp) {
  	if(gs.nil(profileToOps))
  		return; 
  	
  	var context = profileToOps.getContextDefinition().getObjectTypeId();
  	operations[context] = profileToOps.operations();
  	if(hasParentCreateOp) {
  		operations[context].push('create_exist_on_parent');
  	}
  	
  	var children = profileToOps.children();
  	if (!children || children.length <=0)
  		return;
  	
  	for(var i = 0; i < children.length; i++) {
  		var ops = profileToOps.operations();
  		hasParentCreateOp =  ops.length > 0 && ops.indexOf(SMSecurityManager.CREATE) >= 0;		
  		this._getOperationsForProfileAndItsChildren(children[i], operations, hasParentCreateOp);
  	}
  },
  
  //TODO: need to ask SecurityAPI writer for this method
  _findParentContextDefinitionChain: function(context) {
  	var parents = [];
  	var gr = new GlideRecord("svc_security_object_def");
  	gr.addQuery('object_id', context);
  	gr.query();
  	if(gr.next()) {
  		var parent = gr.parent;
  		while(!gs.nil(parent) && parent.object_id != '<root>') {
  			parents.unshift(parent.object_id);
  			parent = parent.parent;
  		}
  		
  		return parents;
  	}
  	throw 'Context definition '+context+' not found';
  },
  
  activeProfiles: function() {
  	this._checkContext();
  	return this._profileDTOs(this.securityContext.activePersonas());
  },
  
  profileMemberships: function() {
  	this._checkContext();
  	return this._profileMembershipDTOs(this.securityContext.memberships());
  },
  
  addProfileMembership: function(profileName, memberName, type) {
  	this._checkContext();
  	this.setProfileMembership(this.securityContext, profileName, memberName, type);
  },
  
  removeProfileMembership: function(profileName, memberName, type) {
  	this._checkContext();
  	this.denyProfileMembership(this.securityContext, profileName, memberName, type);
  },
  
  _profileDTOs : function(profiles) {
  	var dtos = [];
  	for(var i = 0; i < profiles.length; i++) {
  		var dto = {};
  		dto.id = profiles[i].profile ? profiles[i].profile.getSysId() : profiles[i].getSysId();
  		dto.name = profiles[i].profile ? profiles[i].profile.getName() : profiles[i].getName();
  		dto.operations = profiles[i].operations ? profiles[i].operations : [];
  		dtos.push(dto);
  	}
  	dtos.sort(function(a,b) {return a.name.toLowerCase() > b.name.toLowerCase();});
  	return dtos;
  },
  
  _profileMembershipDTOs: function(memberships) {
  	var dtos = {};
  	for(var i = 0; i < memberships.length; i++) {
  		var membership = memberships[i];
  		var profile = membership.getTargetPersona();
  		var forProfileDto = dtos[profile.getSysId()] || [];
  		this._getMembershipDTO(membership, SMSecurityManager.USER, forProfileDto);
  		this._getMembershipDTO(membership, SMSecurityManager.GROUP, forProfileDto);
  		forProfileDto.sort(function(a,b) {return a.member.name.toLowerCase() > b.member.name.toLowerCase();});
  		dtos[profile.getSysId()] = forProfileDto;
  	}
  	for(var profileId in dtos) {
  		if(dtos[profileId].length < 1) {
  			delete dtos[profileId];
  		}
  	}
  	
  	return dtos;
  },
  
  _getMembershipDTO: function(membership, type, forProfileDto) {
  	//we only list the users that are granted permissions defined by the profile
  	var members = membership.getGranted(type);
  	for(var j = 0; j < members.length; j++) {
  		var dto = {};
  		switch(type) {
  			case SMSecurityManager.USER:
  				dto.member = this._getUser('user_name', members[j]);
  				dto.addedTo = this._getContext(membership, type, dto.member.sysId);
  				dto.type = 'User';
  				break;
  			case SMSecurityManager.GROUP:
  				dto.member = this._getGroup('name', members[j]);
  				dto.addedTo = this._getContext(membership, type, dto.member.sysId);
  				dto.type = 'Group';
  				break;
  			default:
  		}			
  		forProfileDto.push(dto);
  	}
  },
  
  //We only handle grant case for now -- GRANT | INHERIT_GRANT
  _getContext: function(membership, type, sysId) {
  	var membershipAction = membership.getAction(type, sysId);
  	var action = membershipAction.getAction();
  	if(action == 'GRANT') {
  		var addedToCtx = membership.getContext();
  		var addedTo = addedToCtx ? addedToCtx.getName() : '';
  		return addedTo;
  	}
  	return this._getContext(membershipAction.getContext(), type, sysId);
  },
  
  _getUser: function(field, value) {
  	var gr = new GlideRecord("sys_user");
  	gr.addQuery(field, value);
  	
  	gr.query();
  	if(gr.next()) {
  		return {
  			sysId : gr.getValue('sys_id'),
  			id : gr.user_name+'',
  			name: gr.getDisplayValue()
  		};
  	}
  	return null;
  },

  _getGroup: function(field, value) {
  	var gr = new GlideRecord("sys_user_group");
  	gr.addQuery(field, value);
  	gr.query();
  	if(gr.next()) {
  		return {
  			sysId : gr.getValue('sys_id'),
  			id : gr.name+'',
  			name: gr.getDisplayValue()
  		};
  	}
  	return null;
  },
  
  _checkContext: function() {
  	if(gs.nil(this.securityContext))
  		throw 'No security context is defined for security manager';
  },
  
  getContextDefinition: function() {
  	/* eslint-disable no-undef */
  	var ctxDefinition = sn_svcmod.ServiceSecurityFactory.loadObjectTypeDefinitions();
  	/* eslint-enable no-undef */
  	var parentCtxs = this._findParentContextDefinitionChain(this.context);
  	for(var i = 0; i < parentCtxs.length; i++) {
  		ctxDefinition = ctxDefinition.getChild(parentCtxs[i]);
  	}
  	return ctxDefinition.getChild(this.context);
  },

  type: 'SMSecurityManager'
};

Sys ID

415735c9c3f12200e2ddb59af3d3ae92

Offical Documentation

Official Docs: