001: /*
002: * Copyright 2006 Luca Garulli (luca.garulli@assetdata.it)
003: *
004: * Licensed under the Apache License, Version 2.0 (the "License");
005: * you may not use this file except in compliance with the License.
006: * You may obtain a copy of the License at
007: *
008: * http://www.apache.org/licenses/LICENSE-2.0
009: *
010: * Unless required by applicable law or agreed to in writing, software
011: * distributed under the License is distributed on an "AS IS" BASIS,
012: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013: * See the License for the specific language governing permissions and
014: * limitations under the License.
015: */
016:
017: package org.romaframework.module.users;
018:
019: import java.security.NoSuchAlgorithmException;
020: import java.util.ArrayList;
021: import java.util.List;
022: import java.util.Map;
023:
024: import org.romaframework.aspect.authentication.AuthenticationAspectAbstract;
025: import org.romaframework.aspect.authentication.AuthenticationException;
026: import org.romaframework.aspect.authentication.UserObjectPermissionListener;
027: import org.romaframework.aspect.persistence.PersistenceAspect;
028: import org.romaframework.aspect.persistence.QueryByFilter;
029: import org.romaframework.aspect.session.SessionInfo;
030: import org.romaframework.aspect.session.SessionListener;
031: import org.romaframework.core.flow.Controller;
032: import org.romaframework.core.flow.ObjectContext;
033: import org.romaframework.core.schema.SchemaElement;
034: import org.romaframework.core.schema.SchemaField;
035: import org.romaframework.module.admin.InfoHelper;
036: import org.romaframework.module.users.domain.BaseAccount;
037: import org.romaframework.module.users.domain.BaseFunction;
038: import org.romaframework.module.users.domain.BaseProfile;
039:
040: public class UsersAuthentication extends AuthenticationAspectAbstract
041: implements UserObjectPermissionListener, SessionListener {
042:
043: public static final String PAR_ALGORITHM = "algorithm";
044:
045: protected static BaseProfile publicProfile;
046: protected static final int ERROR_SLEEP_TIME = 1000;
047:
048: public Object authenticate(String iUserName, String iUserPasswd,
049: Map<String, String> iParameters)
050: throws AuthenticationException {
051: PersistenceAspect db = ObjectContext.getInstance()
052: .getContextComponent(PersistenceAspect.class);
053:
054: QueryByFilter filter = new QueryByFilter(BaseAccount.class);
055: filter.addItem("name", QueryByFilter.FIELD_EQUALS, iUserName);
056: filter.setMode(PersistenceAspect.FULL_MODE_LOADING);
057: filter.setStrategy(PersistenceAspect.STRATEGY_DETACHING);
058: List<BaseAccount> result = db.query(filter);
059:
060: if (result == null || result.size() == 0)
061: throwException("Account " + iUserName + " not found");
062:
063: BaseAccount account = result.get(0);
064:
065: try {
066: if (!checkPassword(account.getPassword(), iUserPasswd))
067: throwException("User or Password not correct");
068: } catch (NoSuchAlgorithmException e) {
069: e.printStackTrace();
070: }
071:
072: if (account.getStatus() == null
073: || !account
074: .getStatus()
075: .equals(
076: InfoHelper
077: .getInstance()
078: .getInfo(
079: UsersInfoConstants.ACCOUNT_CATEGORY_NAME,
080: "Active")))
081: throwException("Account " + iUserName + " is not active");
082:
083: setCurrentAccount(account);
084: return account;
085: }
086:
087: public boolean checkPassword(String iPassword,
088: String iPasswordToCheck) throws NoSuchAlgorithmException {
089: if (getEncryptionAlgorithm() == null) {
090: // NO ALGORITHM: SIMPLY CHECK IF PASSWORD ARE THE SAME AS STRINGS = NO ENCRYPTION
091: if (iPassword == null && iPasswordToCheck == null)
092: return true;
093:
094: return iPasswordToCheck != null && iPassword != null
095: && iPasswordToCheck.equals(iPassword);
096: } else {
097: // USE THE ALGORITHM RECEIVED
098: return encryptPassword(iPasswordToCheck).equals(iPassword);
099: }
100: }
101:
102: private void throwException(String iMessage)
103: throws AuthenticationException {
104: // WAIT A BIT TO PREVENT BRUTE FORCE ATTACKS
105: try {
106: Thread.sleep(ERROR_SLEEP_TIME);
107: } catch (InterruptedException e) {
108: }
109:
110: throw new AuthenticationException(iMessage);
111: }
112:
113: /**
114: * Implement the algorithm that check if a function is allowed for a user profile. It get the user's profile and go up until the
115: * root.
116: */
117: public boolean allow(Object iProfile, String iFunctionName) {
118: if (iProfile == null)
119: return true;
120:
121: BaseProfile userProfile = (BaseProfile) iProfile;
122:
123: // INSERT ALL PROFILE CHAIN IN A VECTOR TO BE BROWSED JUST AFTER
124: ArrayList<BaseProfile> profiles = new ArrayList<BaseProfile>();
125: BaseProfile profile = userProfile;
126: while (profile != null) {
127: profiles.add(profile);
128: profile = profile.getParent();
129: }
130:
131: Byte mode;
132: if (userProfile.getParent() != null) {
133: // GET AS INITIAL MODE THE ROOT MODE
134: mode = profiles.get(profiles.size() - 1).getMode();
135: } else
136: mode = userProfile.getMode();
137:
138: boolean allowed = mode != null
139: && mode == BaseProfile.MODE_ALLOW_ALL_BUT;
140: BaseFunction function;
141:
142: // BROWSE ALL PROFILES CHECKING FOR THE FUNCTION. IT STARTS FROM CURRENT AND
143: // GO UP
144: for (BaseProfile profIter : profiles) {
145: if (profIter.getFunctions() == null)
146: continue;
147:
148: function = profIter.getFunctions().get(iFunctionName);
149: if (function != null) {
150: // FUNCTION FOUND: GET ALLOW MODE AND BREAK
151: allowed = function.isAllow();
152: break;
153: }
154: }
155:
156: return allowed;
157: }
158:
159: public void logout() throws AuthenticationException {
160: }
161:
162: public boolean allowObject(Class<? extends Object> iClass) {
163: BaseProfile profile = getCurrentProfile();
164:
165: return allow(profile, iClass.getSimpleName());
166: }
167:
168: public boolean allowAction(Class<? extends Object> iClass,
169: SchemaElement iAction) {
170: BaseProfile profile = getCurrentProfile();
171: return allow(profile, iClass.getSimpleName() + "."
172: + iAction.getName());
173: }
174:
175: public boolean allowField(Class<? extends Object> iClass,
176: SchemaField iField) {
177: BaseProfile profile = getCurrentProfile();
178: return allow(profile, iClass.getSimpleName() + "."
179: + iField.getName());
180: }
181:
182: private BaseProfile getCurrentProfile() {
183: BaseAccount account = (BaseAccount) getCurrentAccount();
184:
185: if (account == null)
186: return null;
187: else
188: return account.getProfile();
189: }
190:
191: public void onSessionCreating(SessionInfo iSession) {
192: }
193:
194: public void onSessionDestroying(SessionInfo iSession) {
195: logout();
196: }
197:
198: @Override
199: public void startup() {
200: // REGISTER MYSELF AS EVENT LISTENER FROM OBJECTCONTEXT
201: Controller.getInstance().registerListener(
202: UserObjectPermissionListener.class, this );
203: Controller.getInstance().registerListener(
204: SessionListener.class, this );
205:
206: super .startup();
207: }
208:
209: @Override
210: public String getEncryptionAlgorithm() {
211: return DEF_ALGORITHM;
212: }
213: }
|