001package gov.nist.secauto.oscal.lib.model; 002 003import gov.nist.secauto.metaschema.core.datatype.adapter.TokenAdapter; 004import gov.nist.secauto.metaschema.core.datatype.markup.MarkupLine; 005import gov.nist.secauto.metaschema.core.datatype.markup.MarkupLineAdapter; 006import gov.nist.secauto.metaschema.core.model.IBoundObject; 007import gov.nist.secauto.metaschema.core.model.IMetaschemaData; 008import gov.nist.secauto.metaschema.core.model.JsonGroupAsBehavior; 009import gov.nist.secauto.metaschema.core.model.constraint.IConstraint; 010import gov.nist.secauto.metaschema.core.util.ObjectUtils; 011import gov.nist.secauto.metaschema.databind.model.annotations.AllowedValue; 012import gov.nist.secauto.metaschema.databind.model.annotations.AllowedValues; 013import gov.nist.secauto.metaschema.databind.model.annotations.BoundAssembly; 014import gov.nist.secauto.metaschema.databind.model.annotations.BoundField; 015import gov.nist.secauto.metaschema.databind.model.annotations.BoundFlag; 016import gov.nist.secauto.metaschema.databind.model.annotations.Expect; 017import gov.nist.secauto.metaschema.databind.model.annotations.GroupAs; 018import gov.nist.secauto.metaschema.databind.model.annotations.IndexHasKey; 019import gov.nist.secauto.metaschema.databind.model.annotations.KeyField; 020import gov.nist.secauto.metaschema.databind.model.annotations.MetaschemaAssembly; 021import gov.nist.secauto.metaschema.databind.model.annotations.ValueConstraints; 022import gov.nist.secauto.oscal.lib.model.control.catalog.AbstractControl; 023import java.lang.Override; 024import java.lang.String; 025import java.util.LinkedList; 026import java.util.List; 027import org.apache.commons.lang3.builder.ReflectionToStringBuilder; 028import org.apache.commons.lang3.builder.ToStringStyle; 029 030/** 031 * A <a href="https://pages.nist.gov/OSCAL/concepts/terminology/#control">structured object</a> representing a requirement or guideline, which when implemented will reduce an aspect of risk related to an information system and its information. 032 */ 033@MetaschemaAssembly( 034 formalName = "Control", 035 description = "A [structured object](https://pages.nist.gov/OSCAL/concepts/terminology/#control) representing a requirement or guideline, which when implemented will reduce an aspect of risk related to an information system and its information.", 036 name = "control", 037 moduleClass = OscalCatalogModule.class, 038 remarks = "Each security or privacy control within the catalog is defined by a distinct control instance. Controls may be as complex or as simple as a catalog defines them. They may be decomposed or further specified into child `control` objects, for example to represent control enhancements or specific breakouts of control functionality, to be maintained as discrete requirements. Controls may also contain structured parts (using `part`) and they may be grouped together in families or classes with `group`.\n" 039 + "\n" 040 + "Control structures in OSCAL will also exhibit regularities and rules that are not codified in OSCAL but in its applications or domains of application. For example, for catalogs describing controls as defined by NIST SP 800-53, a control must have a part with the name \"statement\", which represents the textual narrative of the control. This \"statement\" part must occur only once, but may have nested parts to allow for multiple paragraphs or sections of text. This organization supports addressability of this data content as long as, and only insofar as, it is consistently implemented across the control set. As given with these model definitions, constraints defined and assigned here can aid in ensuring this regularity; but other such constraints and other useful patterns of use remain to be discovered and described.", 041 valueConstraints = @ValueConstraints(allowedValues = {@AllowedValues(level = IConstraint.Level.ERROR, target = "prop[has-oscal-namespace('http://csrc.nist.gov/ns/oscal')]/@name", values = {@AllowedValue(value = "label", description = "A human-readable label for the parent context, which may be rendered in place of the actual identifier for some use cases."), @AllowedValue(value = "sort-id", description = "An alternative identifier, whose value is easily sortable among other such values in the document."), @AllowedValue(value = "alt-identifier", description = "An alternate or aliased identifier for the parent context."), @AllowedValue(value = "status", description = "The status of a `control`. For example, a value of 'withdrawn' can indicate that the `control` has been withdrawn and should no longer be used.")}), @AllowedValues(level = IConstraint.Level.ERROR, target = "prop[has-oscal-namespace('http://csrc.nist.gov/ns/oscal') and @name='status']/@value", values = {@AllowedValue(value = "withdrawn", description = "The control is no longer used."), @AllowedValue(value = "Withdrawn", description = "\\*\\*(deprecated)\\*\\*\\* Use 'withdrawn' instead.", deprecatedVersion = "1.0.0")}), @AllowedValues(level = IConstraint.Level.ERROR, target = "link/@rel", allowOthers = true, values = {@AllowedValue(value = "reference", description = "The link cites an external resource related to this control."), @AllowedValue(value = "related", description = "The link identifies another control with bearing to this control."), @AllowedValue(value = "required", description = "The link identifies another control that must be present if this control is present."), @AllowedValue(value = "incorporated-into", description = "The link identifies other control content where this control content is now addressed."), @AllowedValue(value = "moved-to", description = "The containing control definition was moved to the referenced control.")}), @AllowedValues(level = IConstraint.Level.ERROR, target = "part[has-oscal-namespace('http://csrc.nist.gov/ns/oscal')]/@name", values = {@AllowedValue(value = "overview", description = "An introduction to a control or a group of controls."), @AllowedValue(value = "statement", description = "A set of implementation requirements or recommendations."), @AllowedValue(value = "guidance", description = "Additional information to consider when selecting, implementing, assessing, and monitoring a control."), @AllowedValue(value = "example", description = "An example of an implemented requirement or control statement."), @AllowedValue(value = "assessment", description = "\\*\\*(deprecated)\\*\\* Use 'assessment-method' instead.", deprecatedVersion = "1.0.1"), @AllowedValue(value = "assessment-method", description = "The part describes a method-based assessment over a set of assessment objects.")}), @AllowedValues(level = IConstraint.Level.ERROR, target = "part[has-oscal-namespace('http://csrc.nist.gov/ns/oscal') and @name='statement']//part[has-oscal-namespace('http://csrc.nist.gov/ns/oscal')]/@name", values = @AllowedValue(value = "item", description = "An individual item within a control statement."), remarks = "Nested statement parts are \"item\" parts."), @AllowedValues(level = IConstraint.Level.ERROR, target = ".//part[has-oscal-namespace('http://csrc.nist.gov/ns/oscal')]/@name", values = {@AllowedValue(value = "objective", description = "\\*\\*(deprecated)\\*\\* Use 'assessment-objective' instead.", deprecatedVersion = "1.0.1"), @AllowedValue(value = "assessment-objective", description = "The part describes a set of assessment objectives.")}, remarks = "Objectives can be nested."), @AllowedValues(level = IConstraint.Level.ERROR, target = "part[has-oscal-namespace('http://csrc.nist.gov/ns/oscal') and @name=('assessment','assessment-method')]/part[has-oscal-namespace('http://csrc.nist.gov/ns/oscal')]/@name", values = {@AllowedValue(value = "objects", description = "\\*\\*(deprecated)\\*\\* Use 'assessment-objects' instead.", deprecatedVersion = "1.0.1"), @AllowedValue(value = "assessment-objects", description = "Provides a listing of assessment objects.")}, remarks = "Assessment objects appear on assessment methods."), @AllowedValues(level = IConstraint.Level.ERROR, target = "part[has-oscal-namespace('http://csrc.nist.gov/ns/oscal') and @name=('assessment','assessment-method')]/prop[has-oscal-namespace('http://csrc.nist.gov/ns/oscal')]/@name", values = @AllowedValue(value = "method", description = "\\*\\*(deprecated)\\*\\* Use 'method' in the 'http://csrc.nist.gov/ns/rmf' namespace. The assessment method to use. This typically appears on parts with the name \"assessment-method\".", deprecatedVersion = "1.0.1")), @AllowedValues(level = IConstraint.Level.ERROR, target = "part[has-oscal-namespace('http://csrc.nist.gov/ns/oscal') and @name=('assessment','assessment-method')]/prop[has-oscal-namespace('http://csrc.nist.gov/ns/rmf')]/@name", values = @AllowedValue(value = "method", description = "The assessment method to use. This typically appears on parts with the name \"assessment-method\".")), @AllowedValues(level = IConstraint.Level.ERROR, target = "part[has-oscal-namespace('http://csrc.nist.gov/ns/oscal') and @name=('assessment','assessment-method')]/prop[has-oscal-namespace(('http://csrc.nist.gov/ns/oscal','http://csrc.nist.gov/ns/rmf')) and @name='method']/@value", values = {@AllowedValue(value = "INTERVIEW", description = "The process of holding discussions with individuals or groups of individuals within an organization to once again, facilitate assessor understanding, achieve clarification, or obtain evidence."), @AllowedValue(value = "EXAMINE", description = "The process of reviewing, inspecting, observing, studying, or analyzing one or more assessment objects (i.e., specifications, mechanisms, or activities)."), @AllowedValue(value = "TEST", description = "The process of exercising one or more assessment objects (i.e., activities or mechanisms) under specified conditions to compare actual with expected behavior.")})}, indexHasKey = @IndexHasKey(level = IConstraint.Level.ERROR, target = "link[@rel=('related','required','incorporated-into','moved-to') and starts-with(@href,'#')]", indexName = "catalog-groups-controls-parts", keyFields = @KeyField(target = "@href", pattern = "#(.*)")), expect = {@Expect(id = "catalog-control-require-statement-when-not-withdrawn", level = IConstraint.Level.ERROR, test = "prop[@name='status']/@value=('withdrawn','Withdrawn') or part[@name='statement']"), @Expect(level = IConstraint.Level.WARNING, target = "part[has-oscal-namespace('http://csrc.nist.gov/ns/oscal') and @name=('assessment','assessment-method')]", test = "prop[has-oscal-namespace(('http://csrc.nist.gov/ns/oscal','http://csrc.nist.gov/ns/rmf')) and @name='method']")}) 042) 043public class Control extends AbstractControl implements IBoundObject { 044 private final IMetaschemaData __metaschemaData; 045 046 /** 047 * "Identifies a control such that it can be referenced in the defining catalog and other OSCAL instances (e.g., profiles)." 048 */ 049 @BoundFlag( 050 formalName = "Control Identifier", 051 description = "Identifies a control such that it can be referenced in the defining catalog and other OSCAL instances (e.g., profiles).", 052 name = "id", 053 required = true, 054 typeAdapter = TokenAdapter.class 055 ) 056 private String _id; 057 058 /** 059 * "A textual label that provides a sub-type or characterization of the control." 060 */ 061 @BoundFlag( 062 formalName = "Control Class", 063 description = "A textual label that provides a sub-type or characterization of the control.", 064 name = "class", 065 typeAdapter = TokenAdapter.class, 066 remarks = "A `class` can be used in validation rules to express extra constraints over named items of a specific `class` value.\n" 067 + "\n" 068 + "A `class` can also be used in an OSCAL profile as a means to target an alteration to control content." 069 ) 070 private String _clazz; 071 072 @BoundField( 073 formalName = "Control Title", 074 description = "A name given to the control, which may be used by a tool for display and navigation.", 075 useName = "title", 076 minOccurs = 1, 077 typeAdapter = MarkupLineAdapter.class 078 ) 079 private MarkupLine _title; 080 081 @BoundAssembly( 082 formalName = "Parameter", 083 description = "Parameters provide a mechanism for the dynamic assignment of value(s) in a control.", 084 useName = "param", 085 maxOccurs = -1, 086 groupAs = @GroupAs(name = "params", inJson = JsonGroupAsBehavior.LIST) 087 ) 088 private List<Parameter> _params; 089 090 @BoundAssembly( 091 formalName = "Property", 092 description = "An attribute, characteristic, or quality of the containing object expressed as a namespace qualified name/value pair.", 093 useName = "prop", 094 maxOccurs = -1, 095 groupAs = @GroupAs(name = "props", inJson = JsonGroupAsBehavior.LIST) 096 ) 097 private List<Property> _props; 098 099 @BoundAssembly( 100 formalName = "Link", 101 description = "A reference to a local or remote resource, that has a specific relation to the containing object.", 102 useName = "link", 103 maxOccurs = -1, 104 groupAs = @GroupAs(name = "links", inJson = JsonGroupAsBehavior.LIST) 105 ) 106 private List<Link> _links; 107 108 @BoundAssembly( 109 formalName = "Part", 110 description = "An annotated, markup-based textual element of a control's or catalog group's definition, or a child of another part.", 111 useName = "part", 112 maxOccurs = -1, 113 groupAs = @GroupAs(name = "parts", inJson = JsonGroupAsBehavior.LIST) 114 ) 115 private List<ControlPart> _parts; 116 117 @BoundAssembly( 118 formalName = "Control", 119 description = "A [structured object](https://pages.nist.gov/OSCAL/concepts/terminology/#control) representing a requirement or guideline, which when implemented will reduce an aspect of risk related to an information system and its information.", 120 useName = "control", 121 maxOccurs = -1, 122 groupAs = @GroupAs(name = "controls", inJson = JsonGroupAsBehavior.LIST) 123 ) 124 private List<Control> _controls; 125 126 public Control() { 127 this(null); 128 } 129 130 public Control(IMetaschemaData data) { 131 this.__metaschemaData = data; 132 } 133 134 @Override 135 public IMetaschemaData getMetaschemaData() { 136 return __metaschemaData; 137 } 138 139 public String getId() { 140 return _id; 141 } 142 143 public void setId(String value) { 144 _id = value; 145 } 146 147 public String getClazz() { 148 return _clazz; 149 } 150 151 public void setClazz(String value) { 152 _clazz = value; 153 } 154 155 public MarkupLine getTitle() { 156 return _title; 157 } 158 159 public void setTitle(MarkupLine value) { 160 _title = value; 161 } 162 163 public List<Parameter> getParams() { 164 return _params; 165 } 166 167 public void setParams(List<Parameter> value) { 168 _params = value; 169 } 170 171 /** 172 * Add a new {@link Parameter} item to the underlying collection. 173 * @param item the item to add 174 * @return {@code true} 175 */ 176 public boolean addParam(Parameter item) { 177 Parameter value = ObjectUtils.requireNonNull(item,"item cannot be null"); 178 if (_params == null) { 179 _params = new LinkedList<>(); 180 } 181 return _params.add(value); 182 } 183 184 /** 185 * Remove the first matching {@link Parameter} item from the underlying collection. 186 * @param item the item to remove 187 * @return {@code true} if the item was removed or {@code false} otherwise 188 */ 189 public boolean removeParam(Parameter item) { 190 Parameter value = ObjectUtils.requireNonNull(item,"item cannot be null"); 191 return _params != null && _params.remove(value); 192 } 193 194 public List<Property> getProps() { 195 return _props; 196 } 197 198 public void setProps(List<Property> value) { 199 _props = value; 200 } 201 202 /** 203 * Add a new {@link Property} item to the underlying collection. 204 * @param item the item to add 205 * @return {@code true} 206 */ 207 public boolean addProp(Property item) { 208 Property value = ObjectUtils.requireNonNull(item,"item cannot be null"); 209 if (_props == null) { 210 _props = new LinkedList<>(); 211 } 212 return _props.add(value); 213 } 214 215 /** 216 * Remove the first matching {@link Property} item from the underlying collection. 217 * @param item the item to remove 218 * @return {@code true} if the item was removed or {@code false} otherwise 219 */ 220 public boolean removeProp(Property item) { 221 Property value = ObjectUtils.requireNonNull(item,"item cannot be null"); 222 return _props != null && _props.remove(value); 223 } 224 225 public List<Link> getLinks() { 226 return _links; 227 } 228 229 public void setLinks(List<Link> value) { 230 _links = value; 231 } 232 233 /** 234 * Add a new {@link Link} item to the underlying collection. 235 * @param item the item to add 236 * @return {@code true} 237 */ 238 public boolean addLink(Link item) { 239 Link value = ObjectUtils.requireNonNull(item,"item cannot be null"); 240 if (_links == null) { 241 _links = new LinkedList<>(); 242 } 243 return _links.add(value); 244 } 245 246 /** 247 * Remove the first matching {@link Link} item from the underlying collection. 248 * @param item the item to remove 249 * @return {@code true} if the item was removed or {@code false} otherwise 250 */ 251 public boolean removeLink(Link item) { 252 Link value = ObjectUtils.requireNonNull(item,"item cannot be null"); 253 return _links != null && _links.remove(value); 254 } 255 256 public List<ControlPart> getParts() { 257 return _parts; 258 } 259 260 public void setParts(List<ControlPart> value) { 261 _parts = value; 262 } 263 264 /** 265 * Add a new {@link ControlPart} item to the underlying collection. 266 * @param item the item to add 267 * @return {@code true} 268 */ 269 public boolean addPart(ControlPart item) { 270 ControlPart value = ObjectUtils.requireNonNull(item,"item cannot be null"); 271 if (_parts == null) { 272 _parts = new LinkedList<>(); 273 } 274 return _parts.add(value); 275 } 276 277 /** 278 * Remove the first matching {@link ControlPart} item from the underlying collection. 279 * @param item the item to remove 280 * @return {@code true} if the item was removed or {@code false} otherwise 281 */ 282 public boolean removePart(ControlPart item) { 283 ControlPart value = ObjectUtils.requireNonNull(item,"item cannot be null"); 284 return _parts != null && _parts.remove(value); 285 } 286 287 public List<Control> getControls() { 288 return _controls; 289 } 290 291 public void setControls(List<Control> value) { 292 _controls = value; 293 } 294 295 /** 296 * Add a new {@link Control} item to the underlying collection. 297 * @param item the item to add 298 * @return {@code true} 299 */ 300 public boolean addControl(Control item) { 301 Control value = ObjectUtils.requireNonNull(item,"item cannot be null"); 302 if (_controls == null) { 303 _controls = new LinkedList<>(); 304 } 305 return _controls.add(value); 306 } 307 308 /** 309 * Remove the first matching {@link Control} item from the underlying collection. 310 * @param item the item to remove 311 * @return {@code true} if the item was removed or {@code false} otherwise 312 */ 313 public boolean removeControl(Control item) { 314 Control value = ObjectUtils.requireNonNull(item,"item cannot be null"); 315 return _controls != null && _controls.remove(value); 316 } 317 318 @Override 319 public String toString() { 320 return new ReflectionToStringBuilder(this, ToStringStyle.MULTI_LINE_STYLE).toString(); 321 } 322}