1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34 package info.magnolia.jaas.sp.jcr;
35
36 import info.magnolia.cms.security.SecurityUtil;
37 import info.magnolia.cms.security.MgnlUser;
38 import info.magnolia.cms.security.MgnlUserManager;
39 import info.magnolia.cms.security.SecuritySupport;
40 import info.magnolia.cms.security.User;
41 import info.magnolia.cms.security.UserManager;
42 import info.magnolia.jaas.sp.AbstractLoginModule;
43 import info.magnolia.jaas.sp.UserAwareLoginModule;
44
45 import java.io.Serializable;
46 import java.util.Arrays;
47 import java.util.Calendar;
48 import java.util.GregorianCalendar;
49 import java.util.TimeZone;
50
51 import javax.security.auth.login.AccountLockedException;
52 import javax.security.auth.login.AccountNotFoundException;
53 import javax.security.auth.login.FailedLoginException;
54 import javax.security.auth.login.LoginException;
55
56 import org.apache.commons.codec.binary.Base64;
57 import org.apache.commons.lang.StringUtils;
58 import org.apache.jackrabbit.value.ValueFactoryImpl;
59 import org.slf4j.Logger;
60 import org.slf4j.LoggerFactory;
61
62
63
64
65 public class JCRAuthenticationModule extends AbstractLoginModule implements UserAwareLoginModule, Serializable {
66
67 private static final Logger log = LoggerFactory.getLogger(JCRAuthenticationModule.class);
68 protected User user;
69
70
71
72
73 public int getMaxAttempts() {
74 String realm;
75 if (this.user instanceof MgnlUser) {
76 realm = ((MgnlUser) user).getRealm();
77
78 } else {
79 return 0;
80 }
81 MgnlUserManager manager = (MgnlUserManager) SecuritySupport.Factory.getInstance().getUserManager(realm);
82 return manager.getMaxFailedLoginAttempts();
83 }
84
85
86
87
88 public long getTimeLock(){
89 String realm;
90 if (this.user instanceof MgnlUser) {
91 realm = ((MgnlUser) user).getRealm();
92 } else {
93
94 return 0;
95 }
96 MgnlUserManager manager = (MgnlUserManager) SecuritySupport.Factory.getInstance().getUserManager(realm);
97 return manager.getLockTimePeriod();
98 }
99
100
101
102
103
104
105
106 @Override
107 public void validateUser() throws LoginException {
108 initUser();
109
110 if (this.user == null) {
111 throw new AccountNotFoundException("User account " + this.name + " not found.");
112 }
113
114 if (!this.user.isEnabled()) {
115 throw new AccountLockedException("User account " + this.name + " is locked.");
116 }
117
118 matchPassword();
119
120 if (!UserManager.ANONYMOUS_USER.equals(user.getName())) {
121
122 getUserManager().updateLastAccessTimestamp(user);
123 }
124 }
125
126 private UserManager getUserManager() {
127
128 log.debug("getting user manager for realm " + realm.getName());
129 return SecuritySupport.Factory.getInstance().getUserManager(realm.getName());
130 }
131
132 protected void initUser() throws LoginException {
133 log.debug("initializing user {}", name);
134
135 long start = System.currentTimeMillis();
136 this.user = getUserManager().getUser(name);
137 log.debug("initialized user {} in {}ms", name, (System.currentTimeMillis() - start));
138 }
139
140 protected void matchPassword() throws LoginException {
141 if(getMaxAttempts() > 0 && !UserManager.ANONYMOUS_USER.equals(user.getName()) && getTimeLock() > 0){
142
143 Calendar currentTime = new GregorianCalendar(TimeZone.getDefault());
144 Calendar lockTime = new GregorianCalendar(TimeZone.getDefault());
145 MgnlUser mgnlUser = (MgnlUser) user;
146 if(mgnlUser.getReleaseTime() != null){
147 lockTime.clear();
148 lockTime.setTime(mgnlUser.getReleaseTime().getTime());
149 }
150 if(lockTime.after(currentTime) && mgnlUser.getReleaseTime() != null){
151 throw new LoginException("User account " + this.name + " is locked until " + mgnlUser.getReleaseTime().getTime() + ".");
152 }
153 }
154 String serverPassword = user.getPassword();
155
156 if (StringUtils.isEmpty(serverPassword)) {
157 throw new FailedLoginException("Magnolia CMS does not allow login to users with no password.");
158 }
159
160 boolean match = false;
161 if (Base64.isArrayByteBase64(serverPassword.getBytes())) {
162 match = Arrays.equals(Base64.decodeBase64(serverPassword), new String(this.pswd).getBytes());
163 } else {
164 match = SecurityUtil.matchBCrypted(new String(this.pswd), serverPassword);
165 }
166 if (!match) {
167 if (getMaxAttempts() > 0 && !UserManager.ANONYMOUS_USER.equals(user.getName())){
168
169 UserManager userManager = getUserManager();
170 MgnlUser mgnlUser = (MgnlUser) user;
171 userManager.setProperty(mgnlUser, "failedLoginAttempts", ValueFactoryImpl.getInstance().createValue((mgnlUser.getFailedLoginAttempts() + 1)));
172
173
174 if (mgnlUser.getFailedLoginAttempts() >= getMaxAttempts() && getTimeLock() <= 0){
175 userManager.setProperty(mgnlUser, "enabled", ValueFactoryImpl.getInstance().createValue(false));
176 userManager.setProperty(mgnlUser, "failedLoginAttempts", ValueFactoryImpl.getInstance().createValue(0));
177 log.warn("Account " + this.name + " was locked due to high number of failed login attempts.");
178
179
180 }else if (mgnlUser.getFailedLoginAttempts() >= getMaxAttempts() && getTimeLock() > 0){
181 userManager.setProperty(mgnlUser, "failedLoginAttempts", ValueFactoryImpl.getInstance().createValue(0));
182 Calendar calendar = new GregorianCalendar(TimeZone.getDefault());
183 calendar.add(Calendar.MINUTE, (int)getTimeLock());
184 userManager.setProperty(mgnlUser, "releaseTime", ValueFactoryImpl.getInstance().createValue(calendar));
185 log.warn("Account " + this.name + " was locked for " + getTimeLock() + " minute(s) due to high number of failed login attempts.");
186 }
187 }
188 throw new FailedLoginException("Passwords do not match");
189 }
190 if(user instanceof MgnlUser){
191 MgnlUser mgnlUser = (MgnlUser) user;
192 UserManager userManager = getUserManager();
193 if (getMaxAttempts() > 0 && !UserManager.ANONYMOUS_USER.equals(mgnlUser.getName()) && mgnlUser.getFailedLoginAttempts() > 0){
194 userManager.setProperty(mgnlUser, "failedLoginAttempts", ValueFactoryImpl.getInstance().createValue(0));
195 }
196 }
197 }
198
199
200
201
202 @Override
203 public void setEntity() {
204
205 this.subject.getPrincipals().add(this.user);
206 this.subject.getPrincipals().add(this.realm);
207
208 collectGroupNames();
209 collectRoleNames();
210 }
211
212
213
214
215 @Override
216 public void setACL() {
217 }
218
219
220
221
222 public void collectRoleNames() {
223 for (String role : this.user.getAllRoles()) {
224 addRoleName(role);
225 }
226 }
227
228
229
230
231 public void collectGroupNames() {
232 for (String group : this.user.getAllGroups()) {
233 addGroupName(group);
234 }
235 }
236
237 @Override
238 public User getUser() {
239 return user;
240 }
241 }