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.security;
18  
19  import io.github.tonywasher.joceanus.gordianknot.api.base.GordianException;
20  import io.github.tonywasher.joceanus.gordianknot.api.factory.GordianFactory;
21  import io.github.tonywasher.joceanus.gordianknot.api.factory.GordianFactory.GordianFactoryLock;
22  import io.github.tonywasher.joceanus.gordianknot.api.factory.GordianFactoryType;
23  import io.github.tonywasher.joceanus.gordianknot.api.keypair.GordianKeyPair;
24  import io.github.tonywasher.joceanus.gordianknot.api.keyset.GordianBadCredentialsException;
25  import io.github.tonywasher.joceanus.gordianknot.api.keyset.GordianKeySet;
26  import io.github.tonywasher.joceanus.gordianknot.api.lock.GordianKeyPairLock;
27  import io.github.tonywasher.joceanus.gordianknot.api.lock.GordianKeySetLock;
28  import io.github.tonywasher.joceanus.gordianknot.api.lock.GordianLockFactory;
29  import io.github.tonywasher.joceanus.gordianknot.api.lock.GordianPasswordLockSpec;
30  import io.github.tonywasher.joceanus.gordianknot.api.zip.GordianZipLock;
31  import io.github.tonywasher.joceanus.gordianknot.util.GordianGenerator;
32  import io.github.tonywasher.joceanus.oceanus.base.OceanusException;
33  import io.github.tonywasher.joceanus.prometheus.exc.PrometheusDataException;
34  import io.github.tonywasher.joceanus.prometheus.exc.PrometheusLogicException;
35  import io.github.tonywasher.joceanus.prometheus.exc.PrometheusSecurityException;
36  
37  import java.nio.ByteBuffer;
38  import java.util.Arrays;
39  
40  /**
41   * Security Manager class which holds a cache of all resolved password hashes. For password
42   * hashes that were not previously resolved, previously used passwords will be attempted. If no
43   * match is found, then the user will be prompted for the password.
44   */
45  public class PrometheusSecurityPasswordManager {
46      /**
47       * Text for Bad Password Error.
48       */
49      private static final String NLS_ERRORPASS = PrometheusSecurityResource.SECURITY_BAD_PASSWORD.getValue();
50  
51      /**
52       * Security factory.
53       */
54      private final GordianFactory theFactory;
55  
56      /**
57       * Lock factory.
58       */
59      private final GordianLockFactory theLockFactory;
60  
61      /**
62       * PasswordLockSpec.
63       */
64      private final GordianPasswordLockSpec theLockSpec;
65  
66      /**
67       * The Cache.
68       */
69      private final PrometheusSecurityPasswordCache theCache;
70  
71      /**
72       * Dialog controller.
73       */
74      private PrometheusSecurityDialogController theDialog;
75  
76      /**
77       * Constructor.
78       *
79       * @param pFactory the factory
80       * @param pDialog  the dialog controller
81       * @throws OceanusException on error
82       */
83      public PrometheusSecurityPasswordManager(final GordianFactory pFactory,
84                                               final PrometheusSecurityDialogController pDialog) throws OceanusException {
85          this(pFactory, new GordianPasswordLockSpec(), pDialog);
86      }
87  
88      /**
89       * Constructor.
90       *
91       * @param pFactory  the factory
92       * @param pLockSpec the lockSpec
93       * @param pDialog   the dialog controller
94       * @throws OceanusException on error
95       */
96      public PrometheusSecurityPasswordManager(final GordianFactory pFactory,
97                                               final GordianPasswordLockSpec pLockSpec,
98                                               final PrometheusSecurityDialogController pDialog) throws OceanusException {
99          /* Allocate the factory */
100         theFactory = pFactory;
101         theLockFactory = theFactory.getLockFactory();
102         theDialog = pDialog;
103         theLockSpec = pLockSpec;
104 
105         /* Allocate a new cache */
106         theCache = new PrometheusSecurityPasswordCache(this, theLockSpec);
107     }
108 
109     /**
110      * Obtain the security factory.
111      *
112      * @return the factory
113      */
114     public GordianFactory getSecurityFactory() {
115         return theFactory;
116     }
117 
118     /**
119      * Obtain the lockSpec.
120      *
121      * @return the lockSpec
122      */
123     public GordianPasswordLockSpec getLockSpec() {
124         return theLockSpec;
125     }
126 
127     /**
128      * Set the dialog controller.
129      *
130      * @param pDialog the controller
131      */
132     public void setDialogController(final PrometheusSecurityDialogController pDialog) {
133         theDialog = pDialog;
134     }
135 
136     /**
137      * Create a new factoryLock.
138      *
139      * @param pSource the description of the secured resource
140      * @return the factoryLock
141      * @throws OceanusException on error
142      */
143     public GordianFactoryLock newFactoryLock(final String pSource) throws OceanusException {
144         /* Protect against exceptions */
145         try {
146             final GordianFactory myFactory = GordianGenerator.createRandomFactory(GordianFactoryType.BC);
147             return (GordianFactoryLock) requestPassword(pSource, true, p -> createFactoryLock(myFactory, p));
148 
149         } catch (GordianException e) {
150             throw new PrometheusSecurityException(e);
151         }
152     }
153 
154     /**
155      * Create a new factoryLock.
156      *
157      * @param pFactory the factory to lock
158      * @param pSource  the description of the secured resource
159      * @return the factoryLock
160      * @throws OceanusException on error
161      */
162     public GordianFactoryLock newFactoryLock(final GordianFactory pFactory,
163                                              final String pSource) throws OceanusException {
164         return (GordianFactoryLock) requestPassword(pSource, true, p -> createFactoryLock(pFactory, p));
165     }
166 
167     /**
168      * Resolve the factoryLock bytes.
169      *
170      * @param pLockBytes the lock bytes to resolve
171      * @param pSource    the description of the secured resource
172      * @return the factoryLock
173      * @throws OceanusException on error
174      */
175     public GordianFactoryLock resolveFactoryLock(final byte[] pLockBytes,
176                                                  final String pSource) throws OceanusException {
177         /* Look up resolved factory */
178         GordianFactoryLock myFactory = theCache.lookUpResolvedFactoryLock(pLockBytes);
179 
180         /* If we have not seen the lock then attempt known passwords */
181         if (myFactory == null) {
182             myFactory = theCache.attemptKnownPasswordsForFactoryLock(pLockBytes);
183         }
184 
185         /* If we have not resolved the lock */
186         if (myFactory == null) {
187             myFactory = (GordianFactoryLock) requestPassword(pSource, false, p -> resolveFactoryLock(pLockBytes, p));
188         }
189 
190         /* Return the resolved factoryLock */
191         return myFactory;
192     }
193 
194     /**
195      * obtain new locked factory (same password).
196      *
197      * @param pReference the reference to clone password from
198      * @return the similar factoryLock
199      * @throws OceanusException on error
200      */
201     public GordianFactoryLock similarFactoryLock(final Object pReference) throws OceanusException {
202         /* Protect against exceptions */
203         try {
204             /* Create a new random factory */
205             final GordianFactory myFactory = GordianGenerator.createRandomFactory(GordianFactoryType.BC);
206 
207             /* LookUp the password */
208             final ByteBuffer myPassword = theCache.lookUpResolvedPassword(pReference);
209 
210             /* Create a similar factoryLock */
211             return theCache.createSimilarFactoryLock(myFactory, myPassword);
212 
213         } catch (GordianException e) {
214             throw new PrometheusSecurityException(e);
215         }
216     }
217 
218     /**
219      * Create a new keySetLock.
220      *
221      * @param pSource the description of the secured resource
222      * @return the keySetLock
223      * @throws OceanusException on error
224      */
225     public GordianKeySetLock newKeySetLock(final String pSource) throws OceanusException {
226         /* Protect against exceptions */
227         try {
228             final GordianKeySet myKeySet = theFactory.getKeySetFactory().generateKeySet(theLockSpec.getKeySetSpec());
229             return (GordianKeySetLock) requestPassword(pSource, true, p -> createKeySetLock(myKeySet, p));
230 
231         } catch (GordianException e) {
232             throw new PrometheusSecurityException(e);
233         }
234     }
235 
236     /**
237      * Create a new keySetLock.
238      *
239      * @param pKeySet the keySet to lock
240      * @param pSource the description of the secured resource
241      * @return the keySetLock
242      * @throws OceanusException on error
243      */
244     public GordianKeySetLock newKeySetLock(final GordianKeySet pKeySet,
245                                            final String pSource) throws OceanusException {
246         return (GordianKeySetLock) requestPassword(pSource, true, p -> createKeySetLock(pKeySet, p));
247     }
248 
249     /**
250      * Resolve the keySetLock bytes.
251      *
252      * @param pLockBytes the lock bytes to resolve
253      * @param pSource    the description of the secured resource
254      * @return the keySetLock
255      * @throws OceanusException on error
256      */
257     public GordianKeySetLock resolveKeySetLock(final byte[] pLockBytes,
258                                                final String pSource) throws OceanusException {
259         /* Look up resolved keySet */
260         GordianKeySetLock myKeySet = theCache.lookUpResolvedKeySetLock(pLockBytes);
261 
262         /* If we have not seen the lock then attempt known passwords */
263         if (myKeySet == null) {
264             myKeySet = theCache.attemptKnownPasswordsForKeySetLock(pLockBytes);
265         }
266 
267         /* If we have not resolved the lock */
268         if (myKeySet == null) {
269             myKeySet = (GordianKeySetLock) requestPassword(pSource, false, p -> resolveKeySetLock(pLockBytes, p));
270         }
271 
272         /* Return the resolved keySetLock */
273         return myKeySet;
274     }
275 
276     /**
277      * obtain new locked keySet (same password).
278      *
279      * @param pReference the reference to clone password from
280      * @return the similar keySetLock
281      * @throws OceanusException on error
282      */
283     public GordianKeySetLock similarKeySetLock(final Object pReference) throws OceanusException {
284         /* Protect against exceptions */
285         try {
286             /* Create a new random keySet */
287             final GordianKeySet myKeySet = theFactory.getKeySetFactory().generateKeySet(theLockSpec.getKeySetSpec());
288 
289             /* LookUp the password */
290             final ByteBuffer myPassword = theCache.lookUpResolvedPassword(pReference);
291 
292             /* Create a similar keySetLock */
293             return theCache.createSimilarKeySetLock(myKeySet, myPassword);
294 
295         } catch (GordianException e) {
296             throw new PrometheusSecurityException(e);
297         }
298     }
299 
300     /**
301      * Create a new keyPairLock.
302      *
303      * @param pKeyPair the keyPair
304      * @param pSource  the description of the secured resource
305      * @return the keyPairLock
306      * @throws OceanusException on error
307      */
308     public GordianKeyPairLock newKeyPairLock(final GordianKeyPair pKeyPair,
309                                              final String pSource) throws OceanusException {
310         return (GordianKeyPairLock) requestPassword(pSource, true, p -> createKeyPairLock(pKeyPair, p));
311     }
312 
313     /**
314      * Resolve the keyPairLock.
315      *
316      * @param pLockBytes the LockBytes to resolve
317      * @param pKeyPair   the keyPair
318      * @param pSource    the description of the secured resource
319      * @return the keyPairLock
320      * @throws OceanusException on error
321      */
322     public GordianKeyPairLock resolveKeyPairLock(final byte[] pLockBytes,
323                                                  final GordianKeyPair pKeyPair,
324                                                  final String pSource) throws OceanusException {
325         /* Look up resolved keySet */
326         GordianKeyPairLock myKeyPair = theCache.lookUpResolvedKeyPairLock(pLockBytes, pKeyPair);
327 
328         /* If we have not seen the lock then attempt known passwords */
329         if (myKeyPair == null) {
330             myKeyPair = theCache.attemptKnownPasswordsForKeyPairLock(pLockBytes, pKeyPair);
331         }
332 
333         /* If we have not resolved the lock */
334         if (myKeyPair == null) {
335             myKeyPair = (GordianKeyPairLock) requestPassword(pSource, false, p -> resolveKeyPairLock(pLockBytes, pKeyPair, p));
336         }
337 
338         /* Return the resolved keyPairLock */
339         return myKeyPair;
340     }
341 
342     /**
343      * obtain similar (same password) zipLock.
344      *
345      * @param pKeyPair   the keyPair
346      * @param pReference the reference to clone password from
347      * @return the similar keyPairLock
348      * @throws OceanusException on error
349      */
350     public GordianKeyPairLock similarKeyPairLock(final GordianKeyPair pKeyPair,
351                                                  final Object pReference) throws OceanusException {
352         /* LookUp the password */
353         final ByteBuffer myPassword = theCache.lookUpResolvedPassword(pReference);
354 
355         /* Create a similar keyPairLock */
356         return theCache.createSimilarKeyPairLock(pKeyPair, myPassword);
357     }
358 
359     /**
360      * Resolve the zipLock.
361      *
362      * @param pZipLock the hash bytes to resolve
363      * @param pSource  the description of the secured resource
364      * @throws OceanusException on error
365      */
366     public void resolveZipLock(final GordianZipLock pZipLock,
367                                final String pSource) throws OceanusException {
368         switch (pZipLock.getLockType()) {
369             case KEYSET_PASSWORD:
370                 resolveKeySetZipLock(pZipLock, pSource);
371                 break;
372             case FACTORY_PASSWORD:
373                 resolveFactoryZipLock(pZipLock, pSource);
374                 break;
375             case KEYPAIR_PASSWORD:
376             default:
377                 throw new PrometheusLogicException("KeyPair zipLock not supported yet");
378         }
379     }
380 
381     /**
382      * Resolve a keySet ZipLock.
383      *
384      * @param pZipLock the zipLock
385      * @param pSource  the description of the secured resource
386      * @throws OceanusException on error
387      */
388     private void resolveKeySetZipLock(final GordianZipLock pZipLock,
389                                       final String pSource) throws OceanusException {
390         /* Protect against exceptions */
391         try {
392             /* Access lockBytes */
393             final byte[] myLockBytes = pZipLock.getLockBytes();
394 
395             /* Look up resolved keySet */
396             final GordianKeySetLock myLock = resolveKeySetLock(myLockBytes, pSource);
397 
398             /* If we resolved the lock */
399             if (myLock != null) {
400                 pZipLock.unlock(myLock);
401             }
402 
403         } catch (GordianException e) {
404             throw new PrometheusSecurityException(e);
405         }
406     }
407 
408     /**
409      * Resolve a factory ZipLock.
410      *
411      * @param pZipLock the zipLock
412      * @param pSource  the description of the secured resource
413      * @throws OceanusException on error
414      */
415     private void resolveFactoryZipLock(final GordianZipLock pZipLock,
416                                        final String pSource) throws OceanusException {
417         /* Protect against exceptions */
418         try {
419             /* Access lockBytes */
420             final byte[] myLockBytes = pZipLock.getLockBytes();
421 
422             /* Look up resolved keySet */
423             final GordianFactoryLock myLock = resolveFactoryLock(myLockBytes, pSource);
424 
425             /* If we resolved the lock */
426             if (myLock != null) {
427                 pZipLock.unlock(myLock);
428             }
429 
430         } catch (GordianException e) {
431             throw new PrometheusSecurityException(e);
432         }
433     }
434 
435     /**
436      * Request password.
437      *
438      * @param pSource      the description of the secured resource
439      * @param pNeedConfirm do we need confirmation
440      * @param pProcessor   the password processor
441      * @return the keySetHash
442      * @throws OceanusException on error
443      */
444     public Object requestPassword(final String pSource,
445                                   final boolean pNeedConfirm,
446                                   final PrometheusProcessPassword pProcessor) throws OceanusException {
447         /* Allocate variables */
448         Object myResult = null;
449 
450         /* Create a new password dialog */
451         theDialog.createTheDialog(pSource, pNeedConfirm);
452 
453         /* Prompt for the password */
454         boolean isPasswordOk = false;
455         char[] myPassword = null;
456         while (theDialog.showTheDialog()) {
457             try {
458                 /* Access the password */
459                 myPassword = theDialog.getPassword();
460 
461                 /* Validate the password */
462                 final String myError = PrometheusPassCheck.validatePassword(myPassword);
463                 if (myError != null) {
464                     theDialog.reportBadPassword(myError);
465                     continue;
466                 }
467 
468                 /* Process the password */
469                 theDialog.showTheSpinner(true);
470                 myResult = pProcessor.processPassword(myPassword);
471 
472                 /* No exception so we are good to go */
473                 isPasswordOk = true;
474                 break;
475 
476             } catch (GordianBadCredentialsException e) {
477                 theDialog.reportBadPassword(NLS_ERRORPASS);
478                 if (myPassword != null) {
479                     Arrays.fill(myPassword, (char) 0);
480                 }
481 
482             } finally {
483                 if (myPassword != null) {
484                     Arrays.fill(myPassword, (char) 0);
485                     myPassword = null;
486                 }
487             }
488         }
489 
490         /* release password resources */
491         theDialog.releaseDialog();
492 
493         /* If we did not get a password */
494         if (!isPasswordOk) {
495             /* Throw an exception */
496             throw new PrometheusDataException(NLS_ERRORPASS);
497         }
498 
499         /* Return the result */
500         return myResult;
501     }
502 
503     /**
504      * Process password interface.
505      */
506     @FunctionalInterface
507     public interface PrometheusProcessPassword {
508         /**
509          * Process password.
510          *
511          * @param pPassword the password
512          * @return the result
513          * @throws OceanusException               on error
514          * @throws GordianBadCredentialsException if password does not match
515          */
516         Object processPassword(char[] pPassword) throws OceanusException;
517     }
518 
519     /**
520      * Create new factoryLock.
521      *
522      * @param pFactory  the factory
523      * @param pPassword the password
524      * @return the new lock
525      * @throws OceanusException on error
526      */
527     private GordianFactoryLock createFactoryLock(final GordianFactory pFactory,
528                                                  final char[] pPassword) throws OceanusException {
529         /* Protect against exceptions */
530         try {
531             final GordianFactoryLock myLock = theFactory.newFactoryLock(pFactory, theLockSpec, pPassword);
532             theCache.addResolvedFactory(myLock, pPassword);
533             return myLock;
534 
535         } catch (GordianException e) {
536             throw new PrometheusSecurityException(e);
537         }
538     }
539 
540     /**
541      * Resolve password for factoryLock.
542      *
543      * @param pLockBytes the lock bytes
544      * @param pPassword  the password
545      * @return the resolved lock
546      * @throws OceanusException on error
547      */
548     private GordianFactoryLock resolveFactoryLock(final byte[] pLockBytes,
549                                                   final char[] pPassword) throws OceanusException {
550         /* Protect against exceptions */
551         try {
552             final GordianFactoryLock myFactory = theFactory.resolveFactoryLock(pLockBytes, pPassword);
553             theCache.addResolvedFactory(myFactory, pPassword);
554             return myFactory;
555 
556         } catch (GordianException e) {
557             throw new PrometheusSecurityException(e);
558         }
559     }
560 
561     /**
562      * Create new keySetLock.
563      *
564      * @param pKeySet   the keySet
565      * @param pPassword the password
566      * @return the new lock
567      * @throws OceanusException on error
568      */
569     private GordianKeySetLock createKeySetLock(final GordianKeySet pKeySet,
570                                                final char[] pPassword) throws OceanusException {
571         /* Protect against exceptions */
572         try {
573             final GordianKeySetLock myLock = theLockFactory.newKeySetLock(pKeySet, theLockSpec, pPassword);
574             theCache.addResolvedKeySet(myLock, pPassword);
575             return myLock;
576 
577         } catch (GordianException e) {
578             throw new PrometheusSecurityException(e);
579         }
580     }
581 
582     /**
583      * Resolve password for keySetLock.
584      *
585      * @param pLockBytes the lock bytes
586      * @param pPassword  the password
587      * @return the resolved lock
588      * @throws OceanusException on error
589      */
590     private GordianKeySetLock resolveKeySetLock(final byte[] pLockBytes,
591                                                 final char[] pPassword) throws OceanusException {
592         /* Protect against exceptions */
593         try {
594             final GordianKeySetLock myKeySet = theLockFactory.resolveKeySetLock(pLockBytes, pPassword);
595             theCache.addResolvedKeySet(myKeySet, pPassword);
596             return myKeySet;
597 
598         } catch (GordianException e) {
599             throw new PrometheusSecurityException(e);
600         }
601     }
602 
603     /**
604      * Create new keyPairLock.
605      *
606      * @param pKeyPair  the keyPair
607      * @param pPassword the password
608      * @return the new lock
609      * @throws OceanusException on error
610      */
611     private GordianKeyPairLock createKeyPairLock(final GordianKeyPair pKeyPair,
612                                                  final char[] pPassword) throws OceanusException {
613         /* Protect against exceptions */
614         try {
615             final GordianKeyPairLock myLock = theLockFactory.newKeyPairLock(theLockSpec, pKeyPair, pPassword);
616             theCache.addResolvedKeyPair(myLock, pPassword);
617             return myLock;
618 
619         } catch (GordianException e) {
620             throw new PrometheusSecurityException(e);
621         }
622     }
623 
624     /**
625      * Resolve password for keyPairLock.
626      *
627      * @param pLockBytes the lock bytes
628      * @param pKeyPair   the keyPair
629      * @param pPassword  the password
630      * @return the resolved lock
631      * @throws OceanusException on error
632      */
633     private GordianKeyPairLock resolveKeyPairLock(final byte[] pLockBytes,
634                                                   final GordianKeyPair pKeyPair,
635                                                   final char[] pPassword) throws OceanusException {
636         /* Protect against exceptions */
637         try {
638             final GordianKeyPairLock myKeyPair = theLockFactory.resolveKeyPairLock(pLockBytes, pKeyPair, pPassword);
639             theCache.addResolvedKeyPair(myKeyPair, pPassword);
640             return myKeyPair;
641 
642         } catch (GordianException e) {
643             throw new PrometheusSecurityException(e);
644         }
645     }
646 
647     /**
648      * Password Check enum.
649      */
650     private enum PrometheusPassCheck {
651         /**
652          * Numeric.
653          */
654         NUMERIC(1),
655 
656         /**
657          * Lowercase.
658          */
659         LOWERCASE(2),
660 
661         /**
662          * Numeric.
663          */
664         UPPERCASE(4),
665 
666         /**
667          * Special.
668          */
669         SPECIAL(8);
670 
671         /**
672          * Text for Bad Length Error.
673          */
674         private static final String NLS_BADLENGTH = PrometheusSecurityResource.SECURITY_BAD_PASSLEN.getValue();
675 
676         /**
677          * Text for Invalid characters Error.
678          */
679         private static final String NLS_BADCHAR = PrometheusSecurityResource.SECURITY_INVALID_CHARS.getValue();
680 
681         /**
682          * Special characters.
683          */
684         private static final String SPECIAL_CHARS = "%$^!@-_+~#&*";
685 
686         /**
687          * Minimum password length.
688          */
689         private static final int MINPASSLEN = 8;
690 
691         /**
692          * The flag.
693          */
694         private final int theFlag;
695 
696         /**
697          * Constructor.
698          *
699          * @param pFlag the flag
700          */
701         PrometheusPassCheck(final int pFlag) {
702             theFlag = pFlag;
703         }
704 
705         /**
706          * Obtain the flag.
707          *
708          * @return the flag
709          */
710         private int getFlag() {
711             return theFlag;
712         }
713 
714         /**
715          * Check password.
716          *
717          * @param pPassword the password
718          * @return the error message (or null)
719          */
720         static String validatePassword(final char[] pPassword) {
721             /* Password must be at least 8 characters in length */
722             if (pPassword.length < MINPASSLEN) {
723                 return NLS_BADLENGTH;
724             }
725 
726             /* Loop through the password ensuring that it has at least one of each type */
727             int myResult = 0;
728             for (char c : pPassword) {
729                 if (Character.isDigit(c)) {
730                     myResult |= NUMERIC.getFlag();
731                 } else if (Character.isLowerCase(c)) {
732                     myResult |= LOWERCASE.getFlag();
733                 } else if (Character.isUpperCase(c)) {
734                     myResult |= UPPERCASE.getFlag();
735                 } else if (SPECIAL_CHARS.indexOf(c) != -1) {
736                     myResult |= SPECIAL.getFlag();
737                 }
738             }
739 
740             /* If we do not have at least one of each */
741             if (myResult != getExpectedResult()) {
742                 return NLS_BADCHAR;
743             }
744             return null;
745         }
746 
747         /**
748          * Obtain expected result.
749          *
750          * @return the expected result
751          */
752         private static int getExpectedResult() {
753             int myResult = 0;
754             for (PrometheusPassCheck myCheck : values()) {
755                 myResult |= myCheck.getFlag();
756             }
757             return myResult;
758         }
759     }
760 }