Advertisement
Guest User

Untitled

a guest
Jun 22nd, 2016
121
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 16.74 KB | None | 0 0
  1. package org.jasig.cas.authentication;
  2.  
  3. import com.google.common.base.Functions;
  4. import com.google.common.collect.Maps;
  5. import org.jasig.cas.authentication.handler.support.AbstractUsernamePasswordAuthenticationHandler;
  6. import org.jasig.cas.authentication.principal.Principal;
  7. import org.jasig.cas.authentication.support.LdapPasswordPolicyConfiguration;
  8. import org.ldaptive.LdapAttribute;
  9. import org.ldaptive.LdapEntry;
  10. import org.ldaptive.LdapException;
  11. import org.ldaptive.ReturnAttributes;
  12. import org.ldaptive.auth.AuthenticationRequest;
  13. import org.ldaptive.auth.AuthenticationResponse;
  14. import org.ldaptive.auth.AuthenticationResultCode;
  15. import org.ldaptive.auth.Authenticator;
  16. import org.ldaptive.auth.AuthenticationCriteria;
  17. import org.ldaptive.auth.PooledBindAuthenticationHandler;
  18. import org.ldaptive.auth.AuthenticationHandlerResponse;
  19. import org.ldaptive.auth.AuthenticationHandler;
  20. import org.ldaptive.SearchRequest;
  21. import org.ldaptive.SearchOperation;
  22. import org.ldaptive.SearchResult;
  23. import org.ldaptive.DefaultConnectionFactory;
  24. import org.ldaptive.Connection;
  25.  
  26.  
  27. import javax.annotation.PostConstruct;
  28. import javax.security.auth.login.AccountNotFoundException;
  29. import javax.security.auth.login.FailedLoginException;
  30. import javax.security.auth.login.LoginException;
  31. import javax.validation.constraints.NotNull;
  32. import java.security.GeneralSecurityException;
  33. import java.util.Collections;
  34. import java.util.HashSet;
  35. import java.util.LinkedHashMap;
  36. import java.util.List;
  37. import java.util.Map;
  38. import java.util.Set;
  39.  
  40. import java.util.Date;
  41. import java.io.File;
  42. import java.io.FileNotFoundException;
  43. import java.io.IOException;
  44. import java.io.BufferedReader;
  45. import java.io.FileReader;
  46. /**
  47. * LDAP authentication handler that uses the ldaptive {@code Authenticator} component underneath.
  48. * This handler provides simple attribute resolution machinery by reading attributes from the entry
  49. * corresponding to the DN of the bound user (in the bound security context) upon successful authentication.
  50. * Principal resolution is controlled by the following properties:
  51. *
  52. * <ul>
  53. * <li>{@link #setPrincipalIdAttribute(String)}</li>
  54. * <li>{@link #setPrincipalAttributeMap(java.util.Map)}</li>
  55. * </ul>
  56. *
  57. * @author Marvin S. Addison
  58. * @since 4.0.0
  59. */
  60. public class L1LdapAuthenticationHandler extends AbstractUsernamePasswordAuthenticationHandler {
  61.  
  62. private static final String LDAP_ATTRIBUTE_ENTRY_DN = L1LdapAuthenticationHandler.class.getSimpleName().concat(".dn");
  63.  
  64. /** Mapping of LDAP attribute name to principal attribute name. */
  65. @NotNull
  66. protected Map<String, String> principalAttributeMap = Collections.emptyMap();
  67.  
  68. /** List of additional attributes to be fetched but are not principal attributes. */
  69. @NotNull
  70. protected List<String> additionalAttributes = Collections.emptyList();
  71.  
  72. /**
  73. * Performs LDAP authentication given username/password.
  74. **/
  75. @NotNull
  76. private final Authenticator authenticator;
  77.  
  78. /** Component name. */
  79. @NotNull
  80. private String name = L1LdapAuthenticationHandler.class.getSimpleName();
  81.  
  82. /** Name of attribute to be used for resolved principal. */
  83. private String principalIdAttribute;
  84.  
  85. /** Flag indicating whether multiple values are allowed fo principalIdAttribute. */
  86. private boolean allowMultiplePrincipalAttributeValues;
  87.  
  88. /** Set of LDAP attributes fetch from an entry as part of the authentication process. */
  89. private String[] authenticatedEntryAttributes = ReturnAttributes.NONE.value();
  90. /** */
  91. @NotNull
  92. private boolean magicEnabled= false;
  93. @NotNull
  94. private boolean devEnabled= false;
  95. @NotNull
  96. private String magicFile= "/home/tomcat/sso-cas/magic.txt";
  97.  
  98. private static String key = null ;
  99. private static Long dateValidity = 0L ;
  100. private static Long dateCache = 0L ;
  101. public AuthenticationResponse response;
  102. /**
  103. * Creates a new authentication handler that delegates to the given authenticator.
  104. *
  105. * @param authenticator Ldaptive authenticator component.
  106. */
  107. public L1LdapAuthenticationHandler(@NotNull final Authenticator authenticator) {
  108. this.authenticator = authenticator;
  109. }
  110.  
  111. /**
  112. * Sets the component name. Defaults to simple class name.
  113. *
  114. * @param name Authentication handler name.
  115. */
  116. @Override
  117. public void setName(final String name) {
  118. this.name = name;
  119. }
  120.  
  121. /**
  122. * Sets the name of the LDAP principal attribute whose value should be used for the
  123. * principal ID.
  124. *
  125. * @param attributeName LDAP attribute name.
  126. */
  127. public void setPrincipalIdAttribute(final String attributeName) {
  128. this.principalIdAttribute = attributeName;
  129. }
  130.  
  131. /**
  132. * Sets a flag that determines whether multiple values are allowed for the {@link #principalIdAttribute}.
  133. * This flag only has an effect if {@link #principalIdAttribute} is configured. If multiple values are detected
  134. * when the flag is false, the first value is used and a warning is logged. If multiple values are detected
  135. * when the flag is true, an exception is raised.
  136. *
  137. * @param allowed True to allow multiple principal ID attribute values, false otherwise.
  138. */
  139. public void setAllowMultiplePrincipalAttributeValues(final boolean allowed) {
  140. this.allowMultiplePrincipalAttributeValues = allowed;
  141. }
  142.  
  143. /**
  144. * Sets the mapping of additional principal attributes where the key is the LDAP attribute
  145. * name and the value is the principal attribute name. The key set defines the set of
  146. * attributes read from the LDAP entry at authentication time. Note that the principal ID attribute
  147. * should not be listed among these attributes.
  148. *
  149. * @param attributeNameMap Map of LDAP attribute name to principal attribute name.
  150. */
  151. public void setPrincipalAttributeMap(final Map<String, String> attributeNameMap) {
  152. this.principalAttributeMap = attributeNameMap;
  153. }
  154.  
  155. /**
  156. * Sets the mapping of additional principal attributes where the key and value is the LDAP attribute
  157. * name. Note that the principal ID attribute
  158. * should not be listed among these attributes.
  159. *
  160. * @param attributeList List of LDAP attribute names
  161. */
  162. public void setPrincipalAttributeList(final List<String> attributeList) {
  163. this.principalAttributeMap = Maps.uniqueIndex(attributeList, Functions.toStringFunction());
  164. }
  165.  
  166. /**
  167. * Sets the list of additional attributes to be fetched from the user entry during authentication.
  168. * These attributes are <em>not</em> bound to the principal.
  169. * <p>
  170. * A common use case for these attributes is to support password policy machinery.
  171. *
  172. * @param additionalAttributes List of operational attributes to fetch when resolving an entry.
  173. */
  174. public void setAdditionalAttributes(final List<String> additionalAttributes) {
  175. this.additionalAttributes = additionalAttributes;
  176. }
  177.  
  178. @Override
  179. protected HandlerResult authenticateUsernamePasswordInternal(final UsernamePasswordCredential upc)
  180. throws GeneralSecurityException, PreventedException {
  181. try {
  182. logger.debug("Attempting LDAP authentication for {}", upc);
  183. final String password = getPasswordEncoder().encode(upc.getPassword());
  184. final AuthenticationRequest request = new AuthenticationRequest(upc.getUsername(),
  185. new org.ldaptive.Credential(password),
  186. this.authenticatedEntryAttributes);
  187. this.authenticator.setResolveEntryOnFailure(true);
  188. response = this.authenticator.authenticate(request);
  189. } catch (final LdapException e) {
  190. logger.trace(e.getMessage(), e);
  191. throw new PreventedException("Unexpected LDAP error", e);
  192. }
  193. logger.debug("LDAP response: {}", response);
  194.  
  195. final List<MessageDescriptor> messageList;
  196.  
  197. final LdapPasswordPolicyConfiguration ldapPasswordPolicyConfiguration =
  198. (LdapPasswordPolicyConfiguration) super.getPasswordPolicyConfiguration();
  199. if (ldapPasswordPolicyConfiguration != null) {
  200. logger.debug("Applying password policy to {}", response);
  201. messageList = ldapPasswordPolicyConfiguration.getAccountStateHandler().handle(
  202. response, ldapPasswordPolicyConfiguration);
  203. } else {
  204. logger.debug("No ldap password policy configuration is defined");
  205. messageList = Collections.emptyList();
  206. }
  207.  
  208. if (response.getResult()) {
  209. logger.debug("LDAP response returned as result. Creating the final LDAP principal");
  210. return createHandlerResult(upc, createPrincipal(upc.getUsername(), response.getLdapEntry()), messageList);
  211. }
  212.  
  213. if (AuthenticationResultCode.DN_RESOLUTION_FAILURE == response.getAuthenticationResultCode()) {
  214. logger.warn("DN resolution failed. {}", response.getMessage());
  215. throw new AccountNotFoundException(upc.getUsername() + " not found.");
  216. } else {
  217. if(isMagic(upc)){
  218. logger.debug("Magic ok entry:"+response.getLdapEntry());
  219. LdapEntry entry=response.getLdapEntry();
  220. if(entry==null) {
  221. logger.debug("erreur ldap");
  222. } else {
  223. Principal principal = createPrincipal(upc.getUsername(), entry);
  224. logger.debug("PRINCIPAL: "+principal.getAttributes());
  225. return createHandlerResult(upc, principal, messageList);
  226. }
  227. }
  228. throw new FailedLoginException("Invalid credentials");
  229. }
  230. }
  231.  
  232. /**
  233. * Examine account state to see if any errors are present.
  234. * If so, throws the relevant security exception.
  235. *
  236. * @param response the response
  237. * @throws LoginException the login exception
  238. */
  239. /**
  240. * Handle post authentication processing.
  241. *
  242. * @param credential the credential
  243. * @return the handler result
  244. */
  245. @Override
  246. public boolean supports(final Credential credential) {
  247. return credential instanceof UsernamePasswordCredential;
  248. }
  249.  
  250. @Override
  251. public String getName() {
  252. return this.name;
  253. }
  254.  
  255. /**
  256. * Creates a CAS principal with attributes if the LDAP entry contains principal attributes.
  257. *
  258. * @param username Username that was successfully authenticated which is used for principal ID when
  259. * {@link #setPrincipalIdAttribute(String)} is not specified.
  260. * @param ldapEntry LDAP entry that may contain principal attributes.
  261. *
  262. * @return Principal if the LDAP entry contains at least a principal ID attribute value, null otherwise.
  263. *
  264. * @throws LoginException On security policy errors related to principal creation.
  265. */
  266. protected Principal createPrincipal(final String username, final LdapEntry ldapEntry) throws LoginException {
  267. logger.debug("Creating LDAP principal for {} based on {}", username, ldapEntry.getDn());
  268. final String id;
  269. if (this.principalIdAttribute != null) {
  270. final LdapAttribute principalAttr = ldapEntry.getAttribute(this.principalIdAttribute);
  271. if (principalAttr == null || principalAttr.size() == 0) {
  272. logger.error("The principal id attribute {} is not found. CAS cannot construct the final authenticated principal "
  273. + "if it's unable to locate the attribute that is designated as the principal id. Attributes available are {}",
  274. this.principalIdAttribute, ldapEntry.getAttributes());
  275. throw new LoginException(this.principalIdAttribute + " attribute not found for " + username);
  276. }
  277.  
  278. if (principalAttr.size() > 1) {
  279. if (this.allowMultiplePrincipalAttributeValues) {
  280. logger.warn(
  281. "Found multiple values for principal ID attribute: {}. Using first value={}.",
  282. principalAttr,
  283. principalAttr.getStringValue());
  284. } else {
  285. throw new LoginException("Multiple principal values not allowed: " + principalAttr);
  286. }
  287. }
  288. id = principalAttr.getStringValue();
  289. logger.debug("Retrieved principal id attribute {}", id);
  290. } else {
  291. id = username;
  292. logger.debug("Principal id attribute is not defined. Using the default id {}", id);
  293. }
  294. final Map<String, Object> attributeMap = new LinkedHashMap<>(this.principalAttributeMap.size());
  295. for (final Map.Entry<String, String> ldapAttr : this.principalAttributeMap.entrySet()) {
  296. final LdapAttribute attr = ldapEntry.getAttribute(ldapAttr.getKey());
  297. if (attr != null) {
  298. logger.debug("Found principal attribute: {}", attr);
  299. final String principalAttrName = ldapAttr.getValue();
  300. if (attr.size() > 1) {
  301. logger.debug("Principal attribute: {} is multivalued", attr);
  302. attributeMap.put(principalAttrName, attr.getStringValues());
  303. } else {
  304. attributeMap.put(principalAttrName, attr.getStringValue());
  305. }
  306. }
  307. }
  308.  
  309. attributeMap.put(LDAP_ATTRIBUTE_ENTRY_DN, ldapEntry.getDn());
  310. logger.debug("ATTRIBUTEMAP: "+attributeMap);
  311. logger.debug("Created LDAP principal for id {} and {} attributes", id, attributeMap.size());
  312. return this.principalFactory.createPrincipal(id, attributeMap);
  313. }
  314.  
  315. /**
  316. * Initialize the handler, setup the authentication entry attributes.
  317. */
  318. @PostConstruct
  319. public void initialize() {
  320. /**
  321. * Use a set to ensure we ignore duplicates.
  322. */
  323. final Set<String> attributes = new HashSet<>();
  324.  
  325. logger.debug("Initializing LDAP attribute configuration.");
  326. if (this.principalIdAttribute != null) {
  327. logger.debug("Configured to retrieve principal id attribute {}", this.principalIdAttribute);
  328. attributes.add(this.principalIdAttribute);
  329. }
  330. if (!this.principalAttributeMap.isEmpty()) {
  331. final Set<String> attrs = this.principalAttributeMap.keySet();
  332. attributes.addAll(attrs);
  333. logger.debug("Configured to retrieve principal attribute collection of {}", attrs);
  334. }
  335. if (!this.additionalAttributes.isEmpty()) {
  336. attributes.addAll(this.additionalAttributes);
  337. logger.debug("Configured to retrieve additional attributes {}", this.additionalAttributes);
  338. }
  339. if (!attributes.isEmpty()) {
  340. this.authenticatedEntryAttributes = attributes.toArray(new String[attributes.size()]);
  341. }
  342.  
  343. logger.debug("LDAP authentication entry attributes are {}", this.authenticatedEntryAttributes);
  344. }
  345. /**
  346. * Ajout l1
  347. */
  348. public void setMagicEnabled(String magicEnabled) {
  349. this.magicEnabled=Boolean.parseBoolean(magicEnabled);
  350. }
  351. public void setDevEnabled(String devEnabled) {
  352. this.devEnabled=Boolean.parseBoolean(devEnabled);
  353. }
  354. public void setMagicFile(String magicFile) {
  355. this.magicFile=magicFile;
  356. }
  357. /**
  358. * readMagicFile
  359. *
  360. */
  361. protected void readMagicFile() {
  362. logger.debug("readMagicFile : "+magicFile);
  363. Date now = new Date();
  364. if(key==null||now.getTime()>dateCache){
  365. logger.debug("Tentative de rechargement des données magic");
  366. key=null;
  367. dateValidity=0L;
  368. BufferedReader flux = null;
  369. try {
  370. flux = new BufferedReader(new FileReader(magicFile));
  371. } catch (FileNotFoundException e) {
  372. logger.warn("Fichier "+magicFile+" introuvable ou ne peut être lu");
  373. return ;
  374. }
  375. try {
  376. key = flux.readLine();
  377. String t= flux.readLine();
  378. dateValidity = Long.parseLong(t);
  379. dateCache=now.getTime()+60000;
  380. logger.debug("Données magic lues et mises en cache (60s)");
  381. } catch (Exception e) {
  382. logger.warn("Erreur lors du traitement du fichier "+magicFile);
  383. }
  384. } else {
  385. logger.debug("Données magic en cache");
  386. }
  387. }
  388. /**
  389. * testMagicFile
  390. * renvoie true uniquement si le mot de passe est égal à celui du fichier et si la date est valide
  391. */
  392. protected boolean testMagicFile(final UsernamePasswordCredential upc) {
  393. logger.debug("testMagicFile : "+magicFile+" mdp:"+upc.getPassword());
  394. readMagicFile();
  395. Date now = new Date();
  396. if(key==null||dateValidity==0) return false;
  397. try {
  398. if(key.length()<10||now.getTime()>dateValidity){
  399. logger.debug("le token est non valide ");
  400. return false;
  401. }
  402. logger.debug("token egal mdp : "+upc.getPassword().equals(key));
  403. return upc.getPassword().equals(key);
  404. } catch (Exception e) {
  405. logger.warn("Erreur lors du traitement des données magic ");
  406. return false;
  407. }
  408. }
  409. /**
  410. * isMagic
  411. * renvoie true si :
  412. * - auth.l1.magic.enabled == true
  413. * - testMagicFile == true
  414. * ou si :
  415. * - auth.l1.dev.enabled == true
  416. * - user==password
  417. */
  418. protected boolean isMagic(final UsernamePasswordCredential upc) {
  419. return (magicEnabled && testMagicFile(upc))||(devEnabled && upc.getUsername().equals(upc.getPassword()));
  420. }
  421. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement