1
2
3
4
5
6 package gov.nist.secauto.oscal.lib.profile.resolver.selection;
7
8 import com.fasterxml.jackson.core.Version;
9 import com.fasterxml.jackson.core.util.VersionUtil;
10
11 import gov.nist.secauto.metaschema.core.metapath.item.node.IAssemblyNodeItem;
12 import gov.nist.secauto.metaschema.core.metapath.item.node.IDocumentNodeItem;
13 import gov.nist.secauto.metaschema.core.metapath.item.node.INodeItem;
14 import gov.nist.secauto.metaschema.core.metapath.item.node.IRootAssemblyNodeItem;
15 import gov.nist.secauto.metaschema.core.util.CollectionUtil;
16 import gov.nist.secauto.metaschema.core.util.ObjectUtils;
17 import gov.nist.secauto.oscal.lib.model.BackMatter;
18 import gov.nist.secauto.oscal.lib.model.BackMatter.Resource;
19 import gov.nist.secauto.oscal.lib.model.Catalog;
20 import gov.nist.secauto.oscal.lib.model.CatalogGroup;
21 import gov.nist.secauto.oscal.lib.model.Control;
22 import gov.nist.secauto.oscal.lib.model.Metadata;
23 import gov.nist.secauto.oscal.lib.model.Metadata.Location;
24 import gov.nist.secauto.oscal.lib.model.Metadata.Party;
25 import gov.nist.secauto.oscal.lib.model.Metadata.Role;
26 import gov.nist.secauto.oscal.lib.model.Parameter;
27 import gov.nist.secauto.oscal.lib.model.ProfileImport;
28 import gov.nist.secauto.oscal.lib.profile.resolver.ProfileResolutionEvaluationException;
29 import gov.nist.secauto.oscal.lib.profile.resolver.ProfileResolutionException;
30 import gov.nist.secauto.oscal.lib.profile.resolver.ProfileResolver.UriResolver;
31 import gov.nist.secauto.oscal.lib.profile.resolver.policy.ReferenceCountingVisitor;
32 import gov.nist.secauto.oscal.lib.profile.resolver.support.BasicIndexer;
33 import gov.nist.secauto.oscal.lib.profile.resolver.support.IEntityItem;
34 import gov.nist.secauto.oscal.lib.profile.resolver.support.IIndexer;
35 import gov.nist.secauto.oscal.lib.profile.resolver.support.IIndexer.SelectionStatus;
36
37 import java.net.URI;
38 import java.util.LinkedList;
39 import java.util.List;
40 import java.util.stream.Collectors;
41
42 import edu.umd.cs.findbugs.annotations.NonNull;
43
44 public class Import {
45
46 @NonNull
47 private final IRootAssemblyNodeItem profile;
48 @NonNull
49 private final IAssemblyNodeItem profileImportItem;
50
51 public Import(
52 @NonNull IRootAssemblyNodeItem profile,
53 @NonNull IAssemblyNodeItem profileImportItem) {
54
55 this.profile = profile;
56 this.profileImportItem = profileImportItem;
57 }
58
59 protected IRootAssemblyNodeItem getProfileItem() {
60 return profile;
61 }
62
63 protected IAssemblyNodeItem getProfileImportItem() {
64 return profileImportItem;
65 }
66
67 @NonNull
68 protected ProfileImport getProfileImport() {
69 return ObjectUtils.requireNonNull((ProfileImport) profileImportItem.getValue());
70 }
71
72 private static Catalog toCatalog(@NonNull IDocumentNodeItem catalogDocument) {
73 return (Catalog) INodeItem.toValue(catalogDocument);
74 }
75
76 @NonNull
77 protected IControlFilter newControlFilter() {
78 return IControlFilter.newInstance(getProfileImport());
79 }
80
81 @NonNull
82 protected IIndexer newIndexer() {
83
84
85
86 return new BasicIndexer();
87 }
88
89 @NonNull
90 public IIndexer resolve(
91 @NonNull IDocumentNodeItem importedCatalogDocument,
92 @NonNull Catalog resolvedCatalog,
93 @NonNull UriResolver uriResolver)
94 throws ProfileResolutionException {
95 ProfileImport profileImport = getProfileImport();
96 URI uri = ObjectUtils.requireNonNull(profileImport.getHref(), "profile import href is null");
97
98
99 IControlFilter filter = newControlFilter();
100 IIndexer indexer = newIndexer();
101
102
103 indexer.setSelectionStatus(importedCatalogDocument.getRootAssemblyNodeItem(), SelectionStatus.SELECTED);
104 IControlSelectionState state = new ControlSelectionState(indexer, filter);
105
106 try {
107 ControlSelectionVisitor.instance().visitCatalog(importedCatalogDocument, state);
108
109
110 ReferenceCountingVisitor.instance().visitCatalog(importedCatalogDocument, indexer, uriResolver);
111
112
113 FilterNonSelectedVisitor.instance().visitCatalog(importedCatalogDocument, indexer);
114 } catch (ProfileResolutionEvaluationException ex) {
115 throw new ProfileResolutionException(
116 String.format("Import: Unable to resolve profile import '%s'. %s", uri.toString(), ex.getMessage()), ex);
117 }
118
119 Catalog importedCatalog = toCatalog(importedCatalogDocument);
120 for (Parameter param : CollectionUtil.listOrEmpty(importedCatalog.getParams())) {
121 if (param != null) {
122 resolvedCatalog.addParam(param);
123 }
124 }
125 for (Control control : CollectionUtil.listOrEmpty(importedCatalog.getControls())) {
126 if (control != null) {
127 resolvedCatalog.addControl(control);
128 }
129 }
130 for (CatalogGroup group : CollectionUtil.listOrEmpty(importedCatalog.getGroups())) {
131 if (group != null) {
132 resolvedCatalog.addGroup(group);
133 }
134 }
135
136 generateMetadata(importedCatalogDocument, resolvedCatalog, indexer);
137 generateBackMatter(importedCatalogDocument, resolvedCatalog, indexer);
138 return indexer;
139 }
140
141 private static void generateMetadata(
142 @NonNull IDocumentNodeItem importedCatalogDocument,
143 @NonNull Catalog resolvedCatalog,
144 @NonNull IIndexer indexer) {
145 Metadata importedMetadata = toCatalog(importedCatalogDocument).getMetadata();
146
147 if (importedMetadata != null) {
148 Metadata resolvedMetadata = resolvedCatalog.getMetadata();
149 if (resolvedMetadata == null) {
150 resolvedMetadata = new Metadata();
151 resolvedCatalog.setMetadata(resolvedMetadata);
152 }
153 resolveMetadata(importedMetadata, resolvedMetadata, indexer);
154 }
155 }
156
157 private static void resolveMetadata(
158 @NonNull Metadata imported,
159 @NonNull Metadata resolved,
160 @NonNull IIndexer indexer) {
161 String importedVersion = imported.getOscalVersion();
162 if (importedVersion != null) {
163 Version importOscalVersion = VersionUtil.parseVersion(importedVersion, null, null);
164
165 Version resolvedCatalogVersion
166 = VersionUtil.parseVersion(resolved.getOscalVersion(), null, null);
167
168 if (importOscalVersion.compareTo(resolvedCatalogVersion) > 0) {
169 resolved.setOscalVersion(importOscalVersion.toString());
170 }
171 }
172
173
174 resolved.setRoles(
175 IIndexer.filterDistinct(
176 ObjectUtils.notNull(CollectionUtil.listOrEmpty(resolved.getRoles()).stream()),
177 indexer.getEntitiesByItemType(IEntityItem.ItemType.ROLE),
178 Role::getId)
179 .collect(Collectors.toCollection(LinkedList::new)));
180 resolved.setParties(
181 IIndexer.filterDistinct(
182 ObjectUtils.notNull(CollectionUtil.listOrEmpty(resolved.getParties()).stream()),
183 indexer.getEntitiesByItemType(IEntityItem.ItemType.PARTY),
184 Party::getUuid)
185 .collect(Collectors.toCollection(LinkedList::new)));
186 resolved.setLocations(
187 IIndexer.filterDistinct(
188 ObjectUtils.notNull(CollectionUtil.listOrEmpty(resolved.getLocations()).stream()),
189 indexer.getEntitiesByItemType(IEntityItem.ItemType.LOCATION),
190 Location::getUuid)
191 .collect(Collectors.toCollection(LinkedList::new)));
192 }
193
194 @SuppressWarnings("PMD.AvoidDeeplyNestedIfStmts")
195 private static void generateBackMatter(
196 @NonNull IDocumentNodeItem importedCatalogDocument,
197 @NonNull Catalog resolvedCatalog,
198 @NonNull IIndexer indexer) {
199 BackMatter importedBackMatter = toCatalog(importedCatalogDocument).getBackMatter();
200
201 if (importedBackMatter != null) {
202 BackMatter resolvedBackMatter = resolvedCatalog.getBackMatter();
203
204 List<Resource> resolvedResources = resolvedBackMatter == null ? CollectionUtil.emptyList()
205 : CollectionUtil.listOrEmpty(resolvedBackMatter.getResources());
206
207 List<Resource> resources = IIndexer.filterDistinct(
208 ObjectUtils.notNull(resolvedResources.stream()),
209 indexer.getEntitiesByItemType(IEntityItem.ItemType.RESOURCE),
210 Resource::getUuid)
211 .collect(Collectors.toCollection(LinkedList::new));
212
213 if (!resources.isEmpty()) {
214 if (resolvedBackMatter == null) {
215 resolvedBackMatter = new BackMatter();
216 resolvedCatalog.setBackMatter(resolvedBackMatter);
217 }
218
219 resolvedBackMatter.setResources(resources);
220 }
221 }
222 }
223 }