View Javadoc
1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one
3    * or more contributor license agreements.  See the NOTICE file
4    * distributed with this work for additional information
5    * regarding copyright ownership.  The ASF licenses this file
6    * to you under the Apache License, Version 2.0 (the
7    * "License"); you may not use this file except in compliance
8    * with the License.  You may obtain a copy of the License at
9    *
10   *   http://www.apache.org/licenses/LICENSE-2.0
11   *
12   * Unless required by applicable law or agreed to in writing,
13   * software distributed under the License is distributed on an
14   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15   * KIND, either express or implied.  See the License for the
16   * specific language governing permissions and limitations
17   * under the License.
18   */
19  package org.apache.syncope.core.spring.policy;
20  
21  import java.util.Collection;
22  import java.util.HashSet;
23  import java.util.Objects;
24  import java.util.Set;
25  import java.util.regex.Pattern;
26  import java.util.stream.Collectors;
27  import org.apache.commons.lang3.StringUtils;
28  import org.apache.syncope.common.lib.policy.AccountRuleConf;
29  import org.apache.syncope.common.lib.policy.DefaultAccountRuleConf;
30  import org.apache.syncope.core.persistence.api.entity.Entity;
31  import org.apache.syncope.core.persistence.api.entity.PlainAttr;
32  import org.apache.syncope.core.persistence.api.entity.user.LinkedAccount;
33  import org.apache.syncope.core.persistence.api.entity.user.User;
34  import org.apache.syncope.core.provisioning.api.rules.AccountRule;
35  import org.apache.syncope.core.provisioning.api.rules.AccountRuleConfClass;
36  import org.springframework.transaction.annotation.Transactional;
37  import org.springframework.util.CollectionUtils;
38  
39  @AccountRuleConfClass(DefaultAccountRuleConf.class)
40  public class DefaultAccountRule implements AccountRule {
41  
42      private DefaultAccountRuleConf conf;
43  
44      @Override
45      public void setConf(final AccountRuleConf conf) {
46          if (conf instanceof DefaultAccountRuleConf) {
47              this.conf = DefaultAccountRuleConf.class.cast(conf);
48          } else {
49              throw new IllegalArgumentException(
50                      DefaultAccountRuleConf.class.getName() + " expected, got " + conf.getClass().getName());
51          }
52      }
53  
54      protected void enforce(final String username, final Set<String> wordsNotPermitted) {
55          // check min length
56          if (conf.getMinLength() > 0 && conf.getMinLength() > username.length()) {
57              throw new AccountPolicyException("Username too short");
58          }
59  
60          // check max length
61          if (conf.getMaxLength() > 0 && conf.getMaxLength() < username.length()) {
62              throw new AccountPolicyException("Username too long");
63          }
64  
65          // check words not permitted
66          wordsNotPermitted.stream().
67                  filter(word -> StringUtils.containsIgnoreCase(username, word)).
68                  forEach(item -> {
69                      throw new AccountPolicyException("Used word(s) not permitted");
70                  });
71  
72          // check case
73          if (conf.isAllUpperCase() && !username.equals(username.toUpperCase())) {
74              throw new AccountPolicyException("No lowercase characters permitted");
75          }
76          if (conf.isAllLowerCase() && !username.equals(username.toLowerCase())) {
77              throw new AccountPolicyException("No uppercase characters permitted");
78          }
79  
80          // check pattern
81          Pattern pattern = conf.getPattern() == null ? Entity.ID_PATTERN : Pattern.compile(conf.getPattern());
82          if (!pattern.matcher(username).matches()) {
83              throw new AccountPolicyException("Username does not match pattern");
84          }
85  
86          // check prefix
87          conf.getPrefixesNotPermitted().stream().
88                  filter(username::startsWith).findAny().
89                  ifPresent(item -> {
90                      throw new AccountPolicyException("Prefix not permitted");
91                  });
92  
93          // check suffix
94          conf.getSuffixesNotPermitted().stream().
95                  filter(username::endsWith).findAny().
96                  ifPresent(item -> {
97                      throw new AccountPolicyException("Suffix not permitted");
98                  });
99      }
100 
101     @Override
102     public void enforce(final String username) {
103         Set<String> wordsNotPermitted = new HashSet<>(conf.getWordsNotPermitted());
104         enforce(username, wordsNotPermitted);
105     }
106 
107     @Transactional(readOnly = true)
108     @Override
109     public void enforce(final User user) {
110         Set<String> wordsNotPermitted = new HashSet<>(conf.getWordsNotPermitted());
111         wordsNotPermitted.addAll(
112                 conf.getSchemasNotPermitted().stream().
113                         map(schema -> user.getPlainAttr(schema).
114                         map(PlainAttr::getValuesAsStrings).orElse(null)).
115                         filter(Objects::nonNull).
116                         filter(values -> !CollectionUtils.isEmpty(values)).
117                         flatMap(Collection::stream).
118                         collect(Collectors.toSet()));
119 
120         enforce(user.getUsername(), wordsNotPermitted);
121     }
122 
123     @Transactional(readOnly = true)
124     @Override
125     public void enforce(final LinkedAccount account) {
126         if (StringUtils.isBlank(account.getUsername())) {
127             return;
128         }
129 
130         Set<String> wordsNotPermitted = new HashSet<>(conf.getWordsNotPermitted());
131         wordsNotPermitted.addAll(
132                 conf.getSchemasNotPermitted().stream().
133                         map(schema -> account.getPlainAttr(schema).
134                         map(PlainAttr::getValuesAsStrings).orElse(null)).
135                         filter(Objects::nonNull).
136                         filter(values -> !CollectionUtils.isEmpty(values)).
137                         flatMap(Collection::stream).
138                         collect(Collectors.toSet()));
139 
140         enforce(account.getUsername(), wordsNotPermitted);
141     }
142 }