View Javadoc
1   /**
2    * Copyright (c) 2012-2017, s3auth.com
3    * All rights reserved.
4    *
5    * Redistribution and use in source and binary forms, with or without
6    * modification, are permitted provided that the following conditions
7    * are met: 1) Redistributions of source code must retain the above
8    * copyright notice, this list of conditions and the following
9    * disclaimer. 2) Redistributions in binary form must reproduce the above
10   * copyright notice, this list of conditions and the following
11   * disclaimer in the documentation and/or other materials provided
12   * with the distribution. 3) Neither the name of the s3auth.com nor
13   * the names of its contributors may be used to endorse or promote
14   * products derived from this software without specific prior written
15   * permission.
16   *
17   * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
18   * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT
19   * NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
20   * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
21   * THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
22   * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
23   * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
24   * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25   * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
26   * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
27   * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
28   * OF THE POSSIBILITY OF SUCH DAMAGE.
29   */
30  package com.s3auth.hosts;
31  
32  import com.jcabi.aspects.Immutable;
33  import java.lang.annotation.Documented;
34  import java.lang.annotation.ElementType;
35  import java.lang.annotation.Retention;
36  import java.lang.annotation.RetentionPolicy;
37  import java.lang.annotation.Target;
38  import javax.validation.Constraint;
39  import javax.validation.ConstraintValidator;
40  import javax.validation.ConstraintValidatorContext;
41  import javax.validation.Payload;
42  
43  /**
44   * Configuration of a single domain.
45   *
46   * <p>Implementation must be immutable and thread-safe.
47   *
48   * @author Yegor Bugayenko (yegor@tpc2.com)
49   * @version $Id: 8d2844f0ee881c3df3c52334ad6a5f47276b69b3 $
50   * @since 0.0.1
51   */
52  @Domain.Valid
53  @Immutable
54  public interface Domain {
55  
56      /**
57       * Name of domain.
58       * @return Full name of domain
59       * @see <a href="http://en.wikipedia.org/wiki/Domain_name">Domain Name</a>
60       */
61      String name();
62  
63      /**
64       * Key.
65       * @return AWS key
66       */
67      String key();
68  
69      /**
70       * Secret key.
71       * @return AWS secret key
72       */
73      String secret();
74  
75      /**
76       * Bucket name.
77       * @return S3 bucket name
78       */
79      String bucket();
80  
81      /**
82       * Region of S3 bucket.
83       * @return Region name/endpoint, e.g. "s3-us-west-1"
84       * @see <a href="http://docs.amazonwebservices.com/general/latest/gr/rande.html#s3_region">S3 Regions</a>
85       */
86      String region();
87  
88      /**
89       * Syslog host and port of domain.
90       * @return Syslog host and port
91       */
92      String syslog();
93  
94      @Target(ElementType.TYPE)
95      @Retention(RetentionPolicy.RUNTIME)
96      @Constraint(validatedBy = Domain.Validator.class)
97      @Documented
98      @interface Valid {
99          /**
100          * Message of the validation error.
101          */
102         String message() default "invalid domain";
103         /**
104          * Groups.
105          */
106         Class<?>[] groups() default { };
107         /**
108          * Payload.
109          */
110         Class<? extends Payload>[] payload() default { };
111     }
112 
113     /**
114      * Validator of Domain.
115      */
116     @SuppressWarnings("PMD.NPathComplexity")
117     class Validator implements ConstraintValidator<Domain.Valid, Domain> {
118         @Override
119         public void initialize(final Domain.Valid annotation) {
120             //nothing to do
121         }
122         // @checkstyle CyclomaticComplexity (60 lines)
123         // @checkstyle ExecutableStatementCount (60 lines)
124         @Override
125         public boolean isValid(final Domain domain,
126             final ConstraintValidatorContext ctx) {
127             boolean isValid = true;
128             if (domain.name() == null) {
129                 ctx.buildConstraintViolationWithTemplate(
130                     "domain name is mandatory and can't be NULL"
131                 ).addConstraintViolation();
132                 isValid = false;
133             } else if (!domain.name().matches("\\s*[a-zA-Z0-9\\-\\.]+\\s*")) {
134                 ctx.buildConstraintViolationWithTemplate(
135                     String.format("invalid domain name '%s'", domain.name())
136                 ).addPropertyNode("name").addConstraintViolation();
137                 isValid = false;
138             }
139             if (domain.key() == null) {
140                 ctx.buildConstraintViolationWithTemplate(
141                     "AWS key is mandatory and can't be NULL"
142                 ).addConstraintViolation();
143                 isValid = false;
144             } else if (!domain.key().matches("\\s*[A-Z0-9]{20}\\s*")) {
145                 ctx.buildConstraintViolationWithTemplate(
146                     String.format("invalid AWS key '%s'", domain.key())
147                 ).addPropertyNode("key").addConstraintViolation();
148                 isValid = false;
149             }
150             if (domain.region() == null) {
151                 ctx.buildConstraintViolationWithTemplate(
152                     "AWS S3 region is mandatory and can't be NULL"
153                 ).addConstraintViolation();
154                 isValid = false;
155             } else if (!domain.region().matches("s3[a-z0-9\\-]*")) {
156                 ctx.buildConstraintViolationWithTemplate(
157                     String.format("invalid AWS S3 region '%s'", domain.region())
158                 ).addPropertyNode("region").addConstraintViolation();
159                 isValid = false;
160             }
161             if (domain.secret() == null) {
162                 ctx.buildConstraintViolationWithTemplate(
163                     "AWS secret key is mandatory and can't be NULL"
164                 ).addConstraintViolation();
165                 isValid = false;
166             } else if (!domain.secret()
167                 .matches("\\s*[a-zA-Z0-9\\+/]{40}\\s*")) {
168                 ctx.buildConstraintViolationWithTemplate(
169                     String.format("invalid AWS secret '%s'", domain.secret())
170                 ).addPropertyNode("secret").addConstraintViolation();
171                 isValid = false;
172             }
173             if (domain.syslog() != null
174                 && !domain.syslog()
175                     .matches("\\s*[a-zA-Z0-9\\-\\.]+(:\\d+)?\\s*")
176             ) {
177                 ctx.buildConstraintViolationWithTemplate(
178                     String.format("invalid syslog host '%s'", domain.syslog())
179                 ).addPropertyNode("syslog").addConstraintViolation();
180                 isValid = false;
181             }
182             return isValid;
183         }
184     }
185 
186 }