View Javadoc
1   /*
2    * Prometheus: Application Framework
3    * Copyright 2012-2026. Tony Washer
4    *
5    * Licensed under the Apache License, Version 2.0 (the "License"); you may not
6    * use this file except in compliance with the License.  You may obtain a copy
7    * of the License at
8    *
9    *   http://www.apache.org/licenses/LICENSE-2.0
10   *
11   * Unless required by applicable law or agreed to in writing, software
12   * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
13   * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
14   * License for the specific language governing permissions and limitations under
15   * the License.
16   */
17  package io.github.tonywasher.joceanus.prometheus.data;
18  
19  import io.github.tonywasher.joceanus.gordianknot.api.base.GordianException;
20  import io.github.tonywasher.joceanus.gordianknot.api.keyset.GordianKeySet;
21  import io.github.tonywasher.joceanus.gordianknot.api.keyset.GordianKeySetFactory;
22  import io.github.tonywasher.joceanus.gordianknot.util.GordianUtilities;
23  import io.github.tonywasher.joceanus.metis.data.MetisDataResource;
24  import io.github.tonywasher.joceanus.metis.field.MetisFieldSet;
25  import io.github.tonywasher.joceanus.metis.field.MetisFieldVersionedSet;
26  import io.github.tonywasher.joceanus.oceanus.base.OceanusException;
27  import io.github.tonywasher.joceanus.oceanus.format.OceanusDataFormatter;
28  import io.github.tonywasher.joceanus.prometheus.data.PrometheusCryptographyData.PrometheusControlKeyCtl;
29  import io.github.tonywasher.joceanus.prometheus.data.PrometheusCryptographyData.PrometheusControlKeySetCtl;
30  import io.github.tonywasher.joceanus.prometheus.data.PrometheusCryptographyData.PrometheusDataKeySetCtl;
31  import io.github.tonywasher.joceanus.prometheus.data.PrometheusData.PrometheusDataSetCtl;
32  import io.github.tonywasher.joceanus.prometheus.exc.PrometheusDataException;
33  import io.github.tonywasher.joceanus.prometheus.exc.PrometheusSecurityException;
34  
35  import java.util.Objects;
36  
37  /**
38   * ControlKey definition and list. The Control Key represents the passwordHash that controls
39   * securing of the dataKeys. It maintains a map of the associated DataKeys.
40   *
41   * @author Tony Washer
42   */
43  public class PrometheusDataKeySet
44          extends PrometheusDataItem
45          implements PrometheusDataKeySetCtl {
46      /**
47       * Object name.
48       */
49      public static final String OBJECT_NAME = PrometheusCryptographyDataType.DATAKEYSET.getItemName();
50  
51      /**
52       * List name.
53       */
54      public static final String LIST_NAME = PrometheusCryptographyDataType.DATAKEYSET.getListName();
55  
56      /**
57       * KeySetWrapLength.
58       */
59      public static final int WRAPLEN = GordianUtilities.getMaximumKeySetWrapLength();
60  
61      /**
62       * Report fields.
63       */
64      private static final MetisFieldVersionedSet<PrometheusDataKeySet> FIELD_DEFS = MetisFieldVersionedSet.newVersionedFieldSet(PrometheusDataKeySet.class);
65  
66      /*
67       * FieldIds.
68       */
69      static {
70          FIELD_DEFS.declareLinkField(PrometheusCryptographyDataType.CONTROLKEYSET);
71          FIELD_DEFS.declareByteArrayField(PrometheusDataResource.KEYSET_KEYSETDEF, WRAPLEN);
72          FIELD_DEFS.declareDerivedVersionedField(PrometheusDataResource.KEYSET_KEYSET);
73          FIELD_DEFS.declareDerivedVersionedField(PrometheusDataResource.KEYSET_ENCRYPTOR);
74      }
75  
76      /**
77       * Copy Constructor.
78       *
79       * @param pList   the list the copy belongs to
80       * @param pSource The Key to copy
81       */
82      protected PrometheusDataKeySet(final PrometheusDataKeySetList pList,
83                                     final PrometheusDataKeySet pSource) {
84          /* Set standard values */
85          super(pList, pSource);
86  
87          /* Switch on the LinkStyle */
88          if (Objects.requireNonNull(getStyle()) == PrometheusListStyle.CLONE) {
89              final GordianKeySet myKeySet = pSource.getKeySet();
90              setValueKeySet(myKeySet);
91              setValueEncryptor(pSource.getEncryptor());
92          }
93      }
94  
95      /**
96       * Values constructor.
97       *
98       * @param pList   the List to add to
99       * @param pValues the values constructor
100      * @throws OceanusException on error
101      */
102     private PrometheusDataKeySet(final PrometheusDataKeySetList pList,
103                                  final PrometheusDataValues pValues) throws OceanusException {
104         /* Initialise the item */
105         super(pList, pValues);
106 
107         /* Access the Password manager */
108         final PrometheusDataSetCtl myData = getDataSet();
109         final OceanusDataFormatter myFormatter = myData.getDataFormatter();
110 
111         /* Store the ControlKey */
112         Object myValue = pValues.getValue(PrometheusCryptographyDataType.CONTROLKEYSET);
113         if (myValue instanceof Integer i) {
114             /* Store the integer */
115             setValueControlKeySet(i);
116 
117             /* Resolve the ControlKey */
118             resolveDataLink(PrometheusCryptographyDataType.CONTROLKEYSET, PrometheusCryptographyDataType.CONTROLKEYSET);
119         } else if (myValue instanceof PrometheusControlKeySetCtl ks) {
120             /* Store the controlKey */
121             setValueControlKeySet(ks);
122         }
123 
124         /* Access the controlKey */
125         final PrometheusControlKeySetCtl myControlKeySet = getControlKeySet();
126 
127         /* Store the WrappedKeySetDef */
128         myValue = pValues.getValue(PrometheusDataResource.KEYSET_KEYSETDEF);
129         if (myValue instanceof byte[] ba) {
130             setValueSecuredKeySetDef(ba);
131         }
132 
133         /* Store/Resolve the keySet */
134         myValue = pValues.getValue(PrometheusDataResource.KEYSET_KEYSET);
135         if (myValue instanceof GordianKeySet ks) {
136             setValueKeySet(ks);
137             setValueEncryptor(new PrometheusEncryptor(myFormatter, ks));
138         } else if (getSecuredKeySetDef() != null) {
139             /* Protect against exceptions */
140             try {
141                 final GordianKeySet myKeySet = myControlKeySet.getKeySet().deriveKeySet(getSecuredKeySetDef());
142                 setValueKeySet(myKeySet);
143                 setValueEncryptor(new PrometheusEncryptor(myFormatter, myKeySet));
144             } catch (GordianException e) {
145                 throw new PrometheusSecurityException(e);
146             }
147         }
148 
149         /* Register the DataKeySet */
150         myControlKeySet.registerDataKeySet(this);
151     }
152 
153     /**
154      * Constructor for a new DataKeySet.
155      *
156      * @param pList          the list to which to add the keySet to
157      * @param pControlKeySet the control keySet
158      * @throws OceanusException on error
159      */
160     protected PrometheusDataKeySet(final PrometheusDataKeySetList pList,
161                                    final PrometheusControlKeySetCtl pControlKeySet) throws OceanusException {
162         /* Initialise the item */
163         super(pList, 0);
164 
165         /* Protect against exceptions */
166         try {
167             /* Store the Details */
168             setValueControlKeySet(pControlKeySet);
169 
170             /* Access the Formatter */
171             final PrometheusDataSetCtl myData = getDataSet();
172             final OceanusDataFormatter myFormatter = myData.getDataFormatter();
173 
174             /* Create the KeySet */
175             final GordianKeySetFactory myKeySets = pControlKeySet.getSecurityFactory().getKeySetFactory();
176             final GordianKeySet myKeySet = myKeySets.generateKeySet(getDataSet().getKeySetSpec());
177             setValueKeySet(myKeySet);
178             setValueEncryptor(new PrometheusEncryptor(myFormatter, myKeySet));
179 
180             /* Set the wrappedKeySetDef */
181             setValueSecuredKeySetDef(pControlKeySet.getKeySet().secureKeySet(myKeySet));
182 
183             /* Catch Exceptions */
184         } catch (GordianException
185                  | OceanusException e) {
186             /* Pass on exception */
187             throw new PrometheusDataException(this, ERROR_CREATEITEM, e);
188         }
189     }
190 
191     @Override
192     public MetisFieldSetDef getDataFieldSet() {
193         return FIELD_DEFS;
194     }
195 
196     /**
197      * Get the ControlKey.
198      *
199      * @return the controlKey
200      */
201     public final PrometheusControlKeyCtl getControlKey() {
202         return getControlKeySet().getControlKey();
203     }
204 
205     /**
206      * Get the ControlKeySet.
207      *
208      * @return the controlKeySet
209      */
210     public final PrometheusControlKeySetCtl getControlKeySet() {
211         return getValues().getValue(PrometheusCryptographyDataType.CONTROLKEYSET, PrometheusControlKeySetCtl.class);
212     }
213 
214     /**
215      * Get the ControlKeyId for this item.
216      *
217      * @return the ControlKeyId
218      */
219     public Integer getControlKeySetId() {
220         final PrometheusControlKeySetCtl myKeySet = getControlKeySet();
221         return myKeySet == null
222                 ? null
223                 : myKeySet.getIndexedId();
224     }
225 
226     /**
227      * Get the securedKeySetDef.
228      *
229      * @return the securedKeySetDef
230      */
231     public final byte[] getSecuredKeySetDef() {
232         return getValues().getValue(PrometheusDataResource.KEYSET_KEYSETDEF, byte[].class);
233     }
234 
235     /**
236      * Get the KeySet.
237      *
238      * @return the keySet
239      */
240     public GordianKeySet getKeySet() {
241         return getValues().getValue(PrometheusDataResource.KEYSET_KEYSET, GordianKeySet.class);
242     }
243 
244     /**
245      * Get the Encryptor.
246      *
247      * @return the encryptor
248      */
249     public PrometheusEncryptor getEncryptor() {
250         return getValues().getValue(PrometheusDataResource.KEYSET_ENCRYPTOR, PrometheusEncryptor.class);
251     }
252 
253     /**
254      * Set the ControlKeySet Id.
255      *
256      * @param pId the controlKeySet id
257      * @throws OceanusException on error
258      */
259     private void setValueControlKeySet(final Integer pId) throws OceanusException {
260         getValues().setValue(PrometheusCryptographyDataType.CONTROLKEYSET, pId);
261     }
262 
263     /**
264      * Set the ControlKeySet.
265      *
266      * @param pKeySet the controlKeySet
267      * @throws OceanusException on error
268      */
269     private void setValueControlKeySet(final PrometheusControlKeySetCtl pKeySet) throws OceanusException {
270         getValues().setValue(PrometheusCryptographyDataType.CONTROLKEYSET, pKeySet);
271     }
272 
273     /**
274      * Set the securedKeySetDef.
275      *
276      * @param pValue the securedKeySetDef
277      */
278     private void setValueSecuredKeySetDef(final byte[] pValue) {
279         getValues().setUncheckedValue(PrometheusDataResource.KEYSET_KEYSETDEF, pValue);
280     }
281 
282     /**
283      * Set the keySet.
284      *
285      * @param pValue the keySet
286      */
287     private void setValueKeySet(final GordianKeySet pValue) {
288         getValues().setUncheckedValue(PrometheusDataResource.KEYSET_KEYSET, pValue);
289     }
290 
291     /**
292      * Set the encryptor.
293      *
294      * @param pValue the encryptor
295      */
296     private void setValueEncryptor(final PrometheusEncryptor pValue) {
297         getValues().setUncheckedValue(PrometheusDataResource.KEYSET_ENCRYPTOR, pValue);
298     }
299 
300     @Override
301     public PrometheusDataKeySet getBase() {
302         return (PrometheusDataKeySet) super.getBase();
303     }
304 
305     @Override
306     public PrometheusDataKeySetList getList() {
307         return (PrometheusDataKeySetList) super.getList();
308     }
309 
310     @Override
311     public int compareValues(final PrometheusDataItem pThat) {
312         /* Only sort on id */
313         return 0;
314     }
315 
316     @Override
317     public void resolveDataSetLinks() throws OceanusException {
318         /* Resolve the ControlKey */
319         final PrometheusDataSetCtl myData = getDataSet();
320         resolveDataLink(PrometheusCryptographyDataType.CONTROLKEYSET, PrometheusCryptographyDataType.CONTROLKEYSET);
321         final PrometheusControlKeySetCtl myControlKeySet = getControlKeySet();
322 
323         /* Register the KeySet */
324         myControlKeySet.registerDataKeySet(this);
325     }
326 
327     /**
328      * Delete the old set of DataKeySet and DataKeys.
329      */
330     protected void deleteDataKeySet() {
331         /* Mark this dataKeySet as deleted */
332         setDeleted(true);
333     }
334 
335     /**
336      * DataKeySet List.
337      */
338     public static class PrometheusDataKeySetList
339             extends PrometheusDataList<PrometheusDataKeySet> {
340         /**
341          * Report fields.
342          */
343         private static final MetisFieldSet<PrometheusDataKeySetList> FIELD_DEFS = MetisFieldSet.newFieldSet(PrometheusDataKeySetList.class);
344 
345         /**
346          * Construct an empty CORE list.
347          *
348          * @param pData the DataSet for the list
349          */
350         protected PrometheusDataKeySetList(final PrometheusDataSetCtl pData) {
351             this(pData, PrometheusListStyle.CORE);
352         }
353 
354         /**
355          * Construct an empty generic ControlKey list.
356          *
357          * @param pData  the DataSet for the list
358          * @param pStyle the style of the list
359          */
360         protected PrometheusDataKeySetList(final PrometheusDataSetCtl pData,
361                                            final PrometheusListStyle pStyle) {
362             super(PrometheusDataKeySet.class, pData, PrometheusCryptographyDataType.DATAKEYSET, pStyle);
363         }
364 
365         /**
366          * Constructor for a cloned List.
367          *
368          * @param pSource the source List
369          */
370         private PrometheusDataKeySetList(final PrometheusDataKeySetList pSource) {
371             super(pSource);
372         }
373 
374         @Override
375         public MetisFieldSet<PrometheusDataKeySetList> getDataFieldSet() {
376             return FIELD_DEFS;
377         }
378 
379         @Override
380         public String listName() {
381             return LIST_NAME;
382         }
383 
384         @Override
385         public MetisFieldSet<PrometheusDataKeySet> getItemFields() {
386             return PrometheusDataKeySet.FIELD_DEFS;
387         }
388 
389         @Override
390         public boolean includeDataXML() {
391             return false;
392         }
393 
394         @Override
395         protected PrometheusDataKeySetList getEmptyList(final PrometheusListStyle pStyle) {
396             final PrometheusDataKeySetList myList = new PrometheusDataKeySetList(this);
397             myList.setStyle(pStyle);
398             return myList;
399         }
400 
401         @Override
402         public PrometheusDataKeySetList deriveList(final PrometheusListStyle pStyle) throws OceanusException {
403             return (PrometheusDataKeySetList) super.deriveList(pStyle);
404         }
405 
406         @Override
407         public PrometheusDataKeySetList deriveDifferences(final PrometheusDataSetCtl pDataSet,
408                                                           final PrometheusDataList<?> pOld) {
409             return (PrometheusDataKeySetList) super.deriveDifferences(pDataSet, pOld);
410         }
411 
412         @Override
413         public PrometheusDataKeySet addCopyItem(final PrometheusDataItem pItem) {
414             /* Can only clone a DataKeySet */
415             if (!(pItem instanceof PrometheusDataKeySet)) {
416                 return null;
417             }
418 
419             /* Clone the data key set */
420             final PrometheusDataKeySet mySet = new PrometheusDataKeySet(this, (PrometheusDataKeySet) pItem);
421             add(mySet);
422             return mySet;
423         }
424 
425         @Override
426         public PrometheusDataKeySet addNewItem() {
427             throw new UnsupportedOperationException();
428         }
429 
430         @Override
431         public PrometheusDataKeySet addValuesItem(final PrometheusDataValues pValues) throws OceanusException {
432             /* Create the dataKeySet */
433             final PrometheusDataKeySet mySet = new PrometheusDataKeySet(this, pValues);
434 
435             /* Check that this keyId has not been previously added */
436             if (!isIdUnique(mySet.getIndexedId())) {
437                 mySet.addError(ERROR_DUPLICATE, MetisDataResource.DATA_ID);
438                 throw new PrometheusDataException(mySet, ERROR_VALIDATION);
439             }
440 
441             /* Add to the list */
442             add(mySet);
443 
444             /* Return it */
445             return mySet;
446         }
447 
448         /**
449          * Clone KeySet from a DataBase.
450          *
451          * @param pControlKeySet the ControlKeySet to clone
452          * @param pKeySet        the DataKeySet to clone
453          * @return the new DataKeySet
454          * @throws OceanusException on error
455          */
456         protected PrometheusDataKeySet cloneDataKeySet(final PrometheusDataItem pControlKeySet,
457                                                        final PrometheusDataKeySet pKeySet) throws OceanusException {
458             /* Build data values */
459             final PrometheusDataValues myValues = new PrometheusDataValues(OBJECT_NAME);
460             myValues.addValue(MetisDataResource.DATA_ID, pKeySet.getIndexedId());
461             myValues.addValue(PrometheusCryptographyDataType.CONTROLKEYSET, pControlKeySet);
462             myValues.addValue(PrometheusDataResource.KEYSET_KEYSETDEF, pKeySet.getSecuredKeySetDef());
463             myValues.addValue(PrometheusDataResource.KEYSET_KEYSET, pKeySet.getKeySet());
464 
465             /* Clone the dataKeySet */
466             return addValuesItem(myValues);
467         }
468 
469         @Override
470         public void postProcessOnLoad() throws OceanusException {
471             /* Just sort the list */
472             reSort();
473         }
474 
475         @Override
476         protected PrometheusDataMapItem allocateDataMap() {
477             /* Unused */
478             throw new UnsupportedOperationException();
479         }
480     }
481 }