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
66 public class JCRAuthenticationModule extends AbstractLoginModule implements UserAwareLoginModule, Serializable {
67
68 private static final Logger log = LoggerFactory.getLogger(JCRAuthenticationModule.class);
69 protected User user;
70
71
72
73
74 public int getMaxAttempts() {
75 String realm;
76 if (this.user instanceof MgnlUser) {
77 realm = ((MgnlUser) user).getRealm();
78
79 } else {
80 return 0;
81 }
82 MgnlUserManager manager = (MgnlUserManager) SecuritySupport.Factory.getInstance().getUserManager(realm);
83 return manager.getMaxFailedLoginAttempts();
84 }
85
86
87
88
89 public long getTimeLock(){
90 String realm;
91 if (this.user instanceof MgnlUser) {
92 realm = ((MgnlUser) user).getRealm();
93 } else {
94
95 return 0;
96 }
97 MgnlUserManager manager = (MgnlUserManager) SecuritySupport.Factory.getInstance().getUserManager(realm);
98 return manager.getLockTimePeriod();
99 }
100
101
102
103
104
105
106
107 @Override
108 public void validateUser() throws LoginException {
109 initUser();
110
111 if (this.user == null) {
112 throw new AccountNotFoundException("User account " + this.name + " not found.");
113 }
114
115 if (!this.user.isEnabled()) {
116 throw new AccountLockedException("User account " + this.name + " is locked.");
117 }
118
119 matchPassword();
120
121 if (!UserManager.ANONYMOUS_USER.equals(user.getName())) {
122
123 getUserManager().updateLastAccessTimestamp(user);
124 }
125 }
126
127 private UserManager getUserManager() {
128
129 log.debug("getting user manager for realm " + realm.getName());
130 return SecuritySupport.Factory.getInstance().getUserManager(realm.getName());
131 }
132
133 protected void initUser() throws LoginException {
134 log.debug("initializing user {}", name);
135
136 long start = System.currentTimeMillis();
137 this.user = getUserManager().getUser(name);
138 log.debug("initialized user {} in {}ms", name, (System.currentTimeMillis() - start));
139 }
140
141 protected void matchPassword() throws LoginException {
142 if(getMaxAttempts() > 0 && !UserManager.ANONYMOUS_USER.equals(user.getName()) && getTimeLock() > 0){
143
144 Calendar currentTime = new GregorianCalendar(TimeZone.getDefault());
145 Calendar lockTime = new GregorianCalendar(TimeZone.getDefault());
146 MgnlUser mgnlUser = (MgnlUser) user;
147 if(mgnlUser.getReleaseTime() != null){
148 lockTime.clear();
149 lockTime.setTime(mgnlUser.getReleaseTime().getTime());
150 }
151 if(lockTime.after(currentTime) && mgnlUser.getReleaseTime() != null){
152 throw new LoginException("User account " + this.name + " is locked until " + mgnlUser.getReleaseTime().getTime() + ".");
153 }
154 }
155 String serverPassword = user.getPassword();
156
157 if (StringUtils.isEmpty(serverPassword)) {
158 throw new FailedLoginException("Magnolia CMS does not allow login to users with no password.");
159 }
160
161 boolean match = false;
162 if (Base64.isArrayByteBase64(serverPassword.getBytes())) {
163 match = Arrays.equals(Base64.decodeBase64(serverPassword), new String(this.pswd).getBytes());
164 } else {
165 match = SecurityUtil.matchBCrypted(new String(this.pswd), serverPassword);
166 }
167 if (!match) {
168 if (getMaxAttempts() > 0 && !UserManager.ANONYMOUS_USER.equals(user.getName())){
169
170 UserManager userManager = getUserManager();
171 MgnlUser mgnlUser = (MgnlUser) user;
172 userManager.setProperty(mgnlUser, "failedLoginAttempts", ValueFactoryImpl.getInstance().createValue((mgnlUser.getFailedLoginAttempts() + 1)));
173
174
175 if (mgnlUser.getFailedLoginAttempts() >= getMaxAttempts() && getTimeLock() <= 0){
176 userManager.setProperty(mgnlUser, "enabled", ValueFactoryImpl.getInstance().createValue(false));
177 userManager.setProperty(mgnlUser, "failedLoginAttempts", ValueFactoryImpl.getInstance().createValue(0));
178 log.warn("Account " + this.name + " was locked due to high number of failed login attempts.");
179
180
181 }else if (mgnlUser.getFailedLoginAttempts() >= getMaxAttempts() && getTimeLock() > 0){
182 userManager.setProperty(mgnlUser, "failedLoginAttempts", ValueFactoryImpl.getInstance().createValue(0));
183 Calendar calendar = new GregorianCalendar(TimeZone.getDefault());
184 calendar.add(Calendar.MINUTE, (int)getTimeLock());
185 userManager.setProperty(mgnlUser, "releaseTime", ValueFactoryImpl.getInstance().createValue(calendar));
186 log.warn("Account " + this.name + " was locked for " + getTimeLock() + " minute(s) due to high number of failed login attempts.");
187 }
188 }
189 if(user instanceof MgnlUser){
190 MgnlUser mgnlUser = (MgnlUser) user;
191 UserManager userManager = getUserManager();
192 if (getMaxAttempts() > 0 && !UserManager.ANONYMOUS_USER.equals(mgnlUser.getName()) && mgnlUser.getFailedLoginAttempts() > 0){
193 userManager.setProperty(mgnlUser, "failedLoginAttempts", ValueFactoryImpl.getInstance().createValue(0));
194 }
195 }
196 throw new FailedLoginException("Passwords do not match");
197 }
198 }
199
200
201
202
203 @Override
204 public void setEntity() {
205
206 this.subject.getPrincipals().add(this.user);
207 this.subject.getPrincipals().add(this.realm);
208
209 collectGroupNames();
210 collectRoleNames();
211 }
212
213
214
215
216 @Override
217 public void setACL() {
218 }
219
220
221
222
223 public void collectRoleNames() {
224 for (String role : this.user.getAllRoles()) {
225 addRoleName(role);
226 }
227 }
228
229
230
231
232 public void collectGroupNames() {
233 for (String group : this.user.getAllGroups()) {
234 addGroupName(group);
235 }
236 }
237
238 @Override
239 public User getUser() {
240 return user;
241 }
242 }