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