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