001package gov.nist.secauto.oscal.lib.model; 002 003import gov.nist.secauto.metaschema.binding.model.annotations.AllowedValue; 004import gov.nist.secauto.metaschema.binding.model.annotations.AllowedValues; 005import gov.nist.secauto.metaschema.binding.model.annotations.BoundAssembly; 006import gov.nist.secauto.metaschema.binding.model.annotations.BoundField; 007import gov.nist.secauto.metaschema.binding.model.annotations.BoundFieldValue; 008import gov.nist.secauto.metaschema.binding.model.annotations.BoundFlag; 009import gov.nist.secauto.metaschema.binding.model.annotations.Expect; 010import gov.nist.secauto.metaschema.binding.model.annotations.GroupAs; 011import gov.nist.secauto.metaschema.binding.model.annotations.IndexHasKey; 012import gov.nist.secauto.metaschema.binding.model.annotations.KeyField; 013import gov.nist.secauto.metaschema.binding.model.annotations.MetaschemaAssembly; 014import gov.nist.secauto.metaschema.binding.model.annotations.ValueConstraints; 015import gov.nist.secauto.metaschema.model.common.JsonGroupAsBehavior; 016import gov.nist.secauto.metaschema.model.common.constraint.IConstraint; 017import gov.nist.secauto.metaschema.model.common.datatype.adapter.TokenAdapter; 018import gov.nist.secauto.metaschema.model.common.datatype.markup.MarkupLine; 019import gov.nist.secauto.metaschema.model.common.datatype.markup.MarkupLineAdapter; 020import gov.nist.secauto.metaschema.model.common.util.ObjectUtils; 021import gov.nist.secauto.oscal.lib.model.control.catalog.AbstractControl; 022import java.lang.Override; 023import java.lang.String; 024import java.util.LinkedList; 025import java.util.List; 026import org.apache.commons.lang3.builder.MultilineRecursiveToStringStyle; 027import org.apache.commons.lang3.builder.ReflectionToStringBuilder; 028 029/** 030 * 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. 031 */ 032@MetaschemaAssembly( 033 formalName = "Control", 034 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.", 035 name = "control", 036 metaschema = OscalCatalogMetaschema.class, 037 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" 038 + "\n" 039 + "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." 040) 041@ValueConstraints( 042 allowedValues = { 043 @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.")}), 044 @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.")}), 045 @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.")}), 046 @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."), @AllowedValue(value = "assessment-method", description = "The part describes a method-based assessment over a set of assessment objects.")}), 047 @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."), 048 @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."), @AllowedValue(value = "assessment-objective", description = "The part describes a set of assessment objectives.")}, remarks = "Objectives can be nested."), 049 @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."), @AllowedValue(value = "assessment-objects", description = "Provides a listing of assessment objects.")}, remarks = "Assessment objects appear on assessment methods."), 050 @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\".")), 051 @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\".")), 052 @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.")}) 053 }, 054 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 = "#(.*)")), 055 expect = { 056 @Expect(id = "catalog-control-require-statement-when-not-withdrawn", level = IConstraint.Level.ERROR, test = "prop[@name='status']/@value=('withdrawn','Withdrawn') or part[@name='statement']"), 057 @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']") 058 } 059) 060public class Control extends AbstractControl { 061 @BoundFlag( 062 formalName = "Control Identifier", 063 description = "Identifies a control such that it can be referenced in the defining catalog and other OSCAL instances (e.g., profiles).", 064 useName = "id", 065 required = true, 066 typeAdapter = TokenAdapter.class 067 ) 068 private String _id; 069 070 @BoundFlag( 071 formalName = "Control Class", 072 description = "A textual label that provides a sub-type or characterization of the control.", 073 useName = "class", 074 typeAdapter = TokenAdapter.class, 075 remarks = "A `class` can be used in validation rules to express extra constraints over named items of a specific `class` value.\n" 076 + "\n" 077 + "A `class` can also be used in an OSCAL profile as a means to target an alteration to control content." 078 ) 079 private String _clazz; 080 081 /** 082 * "A name given to the control, which may be used by a tool for display and navigation." 083 */ 084 @BoundField( 085 formalName = "Control Title", 086 description = "A name given to the control, which may be used by a tool for display and navigation.", 087 useName = "title", 088 minOccurs = 1 089 ) 090 @BoundFieldValue( 091 typeAdapter = MarkupLineAdapter.class 092 ) 093 private MarkupLine _title; 094 095 @BoundAssembly( 096 formalName = "Parameter", 097 description = "Parameters provide a mechanism for the dynamic assignment of value(s) in a control.", 098 useName = "param", 099 maxOccurs = -1 100 ) 101 @GroupAs( 102 name = "params", 103 inJson = JsonGroupAsBehavior.LIST 104 ) 105 private List<Parameter> _params; 106 107 @BoundAssembly( 108 formalName = "Property", 109 description = "An attribute, characteristic, or quality of the containing object expressed as a namespace qualified name/value pair.", 110 useName = "prop", 111 maxOccurs = -1 112 ) 113 @GroupAs( 114 name = "props", 115 inJson = JsonGroupAsBehavior.LIST 116 ) 117 private List<Property> _props; 118 119 @BoundAssembly( 120 formalName = "Link", 121 description = "A reference to a local or remote resource, that has a specific relation to the containing object.", 122 useName = "link", 123 maxOccurs = -1 124 ) 125 @GroupAs( 126 name = "links", 127 inJson = JsonGroupAsBehavior.LIST 128 ) 129 private List<Link> _links; 130 131 @BoundAssembly( 132 formalName = "Part", 133 description = "An annotated, markup-based textual element of a control's or catalog group's definition, or a child of another part.", 134 useName = "part", 135 maxOccurs = -1 136 ) 137 @GroupAs( 138 name = "parts", 139 inJson = JsonGroupAsBehavior.LIST 140 ) 141 private List<ControlPart> _parts; 142 143 @BoundAssembly( 144 formalName = "Control", 145 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.", 146 useName = "control", 147 maxOccurs = -1 148 ) 149 @GroupAs( 150 name = "controls", 151 inJson = JsonGroupAsBehavior.LIST 152 ) 153 private List<Control> _controls; 154 155 public Control() { 156 } 157 158 public String getId() { 159 return _id; 160 } 161 162 public void setId(String value) { 163 _id = value; 164 } 165 166 public String getClazz() { 167 return _clazz; 168 } 169 170 public void setClazz(String value) { 171 _clazz = value; 172 } 173 174 public MarkupLine getTitle() { 175 return _title; 176 } 177 178 public void setTitle(MarkupLine value) { 179 _title = value; 180 } 181 182 public List<Parameter> getParams() { 183 return _params; 184 } 185 186 public void setParams(List<Parameter> value) { 187 _params = value; 188 } 189 190 /** 191 * Add a new {@link Parameter} item to the underlying collection. 192 * @param item the item to add 193 * @return {@code true} 194 */ 195 public boolean addParam(Parameter item) { 196 Parameter value = ObjectUtils.requireNonNull(item,"item cannot be null"); 197 if (_params == null) { 198 _params = new LinkedList<>(); 199 } 200 return _params.add(value); 201 } 202 203 /** 204 * Remove the first matching {@link Parameter} item from the underlying collection. 205 * @param item the item to remove 206 * @return {@code true} if the item was removed or {@code false} otherwise 207 */ 208 public boolean removeParam(Parameter item) { 209 Parameter value = ObjectUtils.requireNonNull(item,"item cannot be null"); 210 return _params == null ? false : _params.remove(value); 211 } 212 213 public List<Property> getProps() { 214 return _props; 215 } 216 217 public void setProps(List<Property> value) { 218 _props = value; 219 } 220 221 /** 222 * Add a new {@link Property} item to the underlying collection. 223 * @param item the item to add 224 * @return {@code true} 225 */ 226 public boolean addProp(Property item) { 227 Property value = ObjectUtils.requireNonNull(item,"item cannot be null"); 228 if (_props == null) { 229 _props = new LinkedList<>(); 230 } 231 return _props.add(value); 232 } 233 234 /** 235 * Remove the first matching {@link Property} item from the underlying collection. 236 * @param item the item to remove 237 * @return {@code true} if the item was removed or {@code false} otherwise 238 */ 239 public boolean removeProp(Property item) { 240 Property value = ObjectUtils.requireNonNull(item,"item cannot be null"); 241 return _props == null ? false : _props.remove(value); 242 } 243 244 public List<Link> getLinks() { 245 return _links; 246 } 247 248 public void setLinks(List<Link> value) { 249 _links = value; 250 } 251 252 /** 253 * Add a new {@link Link} item to the underlying collection. 254 * @param item the item to add 255 * @return {@code true} 256 */ 257 public boolean addLink(Link item) { 258 Link value = ObjectUtils.requireNonNull(item,"item cannot be null"); 259 if (_links == null) { 260 _links = new LinkedList<>(); 261 } 262 return _links.add(value); 263 } 264 265 /** 266 * Remove the first matching {@link Link} item from the underlying collection. 267 * @param item the item to remove 268 * @return {@code true} if the item was removed or {@code false} otherwise 269 */ 270 public boolean removeLink(Link item) { 271 Link value = ObjectUtils.requireNonNull(item,"item cannot be null"); 272 return _links == null ? false : _links.remove(value); 273 } 274 275 public List<ControlPart> getParts() { 276 return _parts; 277 } 278 279 public void setParts(List<ControlPart> value) { 280 _parts = value; 281 } 282 283 /** 284 * Add a new {@link ControlPart} item to the underlying collection. 285 * @param item the item to add 286 * @return {@code true} 287 */ 288 public boolean addPart(ControlPart item) { 289 ControlPart value = ObjectUtils.requireNonNull(item,"item cannot be null"); 290 if (_parts == null) { 291 _parts = new LinkedList<>(); 292 } 293 return _parts.add(value); 294 } 295 296 /** 297 * Remove the first matching {@link ControlPart} item from the underlying collection. 298 * @param item the item to remove 299 * @return {@code true} if the item was removed or {@code false} otherwise 300 */ 301 public boolean removePart(ControlPart item) { 302 ControlPart value = ObjectUtils.requireNonNull(item,"item cannot be null"); 303 return _parts == null ? false : _parts.remove(value); 304 } 305 306 public List<Control> getControls() { 307 return _controls; 308 } 309 310 public void setControls(List<Control> value) { 311 _controls = value; 312 } 313 314 /** 315 * Add a new {@link Control} item to the underlying collection. 316 * @param item the item to add 317 * @return {@code true} 318 */ 319 public boolean addControl(Control item) { 320 Control value = ObjectUtils.requireNonNull(item,"item cannot be null"); 321 if (_controls == null) { 322 _controls = new LinkedList<>(); 323 } 324 return _controls.add(value); 325 } 326 327 /** 328 * Remove the first matching {@link Control} item from the underlying collection. 329 * @param item the item to remove 330 * @return {@code true} if the item was removed or {@code false} otherwise 331 */ 332 public boolean removeControl(Control item) { 333 Control value = ObjectUtils.requireNonNull(item,"item cannot be null"); 334 return _controls == null ? false : _controls.remove(value); 335 } 336 337 @Override 338 public String toString() { 339 return new ReflectionToStringBuilder(this, MultilineRecursiveToStringStyle.MULTI_LINE_STYLE).toString(); 340 } 341}