View Javadoc

1   /**
2    * This file Copyright (c) 2003-2011 Magnolia International
3    * Ltd.  (http://www.magnolia-cms.com). All rights reserved.
4    *
5    *
6    * This file is dual-licensed under both the Magnolia
7    * Network Agreement and the GNU General Public License.
8    * You may elect to use one or the other of these licenses.
9    *
10   * This file is distributed in the hope that it will be
11   * useful, but AS-IS and WITHOUT ANY WARRANTY; without even the
12   * implied warranty of MERCHANTABILITY or FITNESS FOR A
13   * PARTICULAR PURPOSE, TITLE, or NONINFRINGEMENT.
14   * Redistribution, except as permitted by whichever of the GPL
15   * or MNA you select, is prohibited.
16   *
17   * 1. For the GPL license (GPL), you can redistribute and/or
18   * modify this file under the terms of the GNU General
19   * Public License, Version 3, as published by the Free Software
20   * Foundation.  You should have received a copy of the GNU
21   * General Public License, Version 3 along with this program;
22   * if not, write to the Free Software Foundation, Inc., 51
23   * Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
24   *
25   * 2. For the Magnolia Network Agreement (MNA), this file
26   * and the accompanying materials are made available under the
27   * terms of the MNA which accompanies this distribution, and
28   * is available at http://www.magnolia-cms.com/mna.html
29   *
30   * Any modifications to this file must keep this entire header
31   * intact.
32   *
33   */
34  package info.magnolia.cms.security;
35  
36  import info.magnolia.cms.security.auth.callback.CredentialsCallbackHandler;
37  import info.magnolia.cms.security.auth.login.LoginResult;
38  
39  import java.security.Principal;
40  import java.util.ArrayList;
41  import java.util.Collection;
42  import java.util.Collections;
43  import java.util.Iterator;
44  
45  import javax.security.auth.Subject;
46  import javax.security.auth.login.LoginContext;
47  import javax.security.auth.login.LoginException;
48  
49  /**
50   * To be used as a replacement of /server/security or SecuritySupportImpl in mgnl-beans.properties
51   * in case the configuration is messed up. For instance, edit
52   * <code>WEB-INF/config/default/magnolia.properties</code> and add
53   * <pre>info.magnolia.cms.security.SecuritySupport=info.magnolia.cms.security.RescueSecuritySupport</pre>
54   *
55   * @author gjoseph
56   * @version $Revision: $ ($Author: $)
57   */
58  public class RescueSecuritySupport extends SecuritySupportBase {
59  
60      private static final org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(RescueSecuritySupport.class);
61      public RescueSecuritySupport() {
62          super();
63          log.warn("Using RescueSecuritySupport !");
64      }
65  
66      @Override
67      public UserManager getUserManager() {
68          log.warn("Using RescueSecuritySupport, will instantiate RescueUserManager, please fix your configuration !");
69          SystemUserManager userManager = new RescueUserManager();
70          userManager.setRealmName(Realm.REALM_SYSTEM.getName());
71          return userManager;
72      }
73  
74      @Override
75      public UserManager getUserManager(String realmName) {
76          log.warn("Using RescueSecuritySupport, will instantiate RescueUserManager, please fix your configuration !");
77          SystemUserManager userManager = new RescueUserManager();
78          userManager.setRealmName(realmName);
79          return userManager;
80      }
81  
82      @Override
83      public GroupManager getGroupManager() {
84          log.warn("Using RescueSecuritySupport, will instantiate MgnlGroupManager, please fix your configuration !");
85          return new MgnlGroupManager();
86      }
87  
88      @Override
89      public RoleManager getRoleManager() {
90          log.warn("Using RescueSecuritySupport, will instantiate MgnlRoleManager, please fix your configuration !");
91          return new MgnlRoleManager();
92      }
93  
94      @Override
95      public LoginResult authenticate(CredentialsCallbackHandler callbackHandler, String customLoginModule) {
96          log.warn("Using RescueSecuritySupport, will force authentication with a fake system user, please fix your configuration !");
97          try {
98              LoginContext loginContext = createLoginContext(callbackHandler, customLoginModule);
99              loginContext.login();
100 
101             Subject subject = loginContext.getSubject();
102             User user = new RescueUser(UserManager.SYSTEM_USER, UserManager.SYSTEM_PSWD);
103             replaceUserPrincipal(subject, user);
104             return new LoginResult(LoginResult.STATUS_SUCCEEDED, subject);
105         } catch (LoginException e) {
106             throw new RuntimeException(e);
107         }
108     }
109 
110     private void replaceUserPrincipal(Subject subject, User user) {
111         Iterator<Principal> iterator = subject.getPrincipals().iterator();
112         while (iterator.hasNext()) {
113             Principal next = iterator.next();
114             if (next instanceof User) {
115                 iterator.remove();
116                 subject.getPrincipals().add(user);
117                 break;
118             }
119         }
120     }
121 
122     /**
123      * TODO: extract as top level class? Currently this class is tested implicitly by {@link RescueSecuritySupportTest}. Should this implement directly UserManager and throw UnsupportedMethodException for the methods not implemented?
124      * <p>Overrides {@link SystemUserManager#getSystemUser()}, {@link SystemUserManager#getAnonymousUser()} and {@link SystemUserManager#getUser(String)}. All methods return an instance of {@link RescueUser}.
125      * @version $Id$
126      */
127     protected class RescueUserManager extends SystemUserManager {
128 
129         @Override
130         public User getSystemUser() {
131             return new RescueUser(SYSTEM_USER, SYSTEM_PSWD);
132         }
133 
134         @Override
135         public User getAnonymousUser() {
136             return new RescueUser(ANONYMOUS_USER, "");
137         }
138         @Override
139         public User getUser(String name) {
140             if(SYSTEM_USER.equals(name)){
141                 return new RescueUser(SYSTEM_USER, SYSTEM_PSWD);
142             }
143             return new RescueUser(ANONYMOUS_USER, "");
144         }
145     }
146 
147     /**
148      * TODO extract as top level class? Currently this class is tested implicitly by {@link RescueSecuritySupportTest}.<p>
149      * A <em>"fake"</em> user, that is a user who is created in-memory rather than relying on a working <em>users</em> repository,
150      * as the latter may be corrupted and in need of being fixed.
151      * <p>See <a href='http://jira.magnolia-cms.com/browse/MAGNOLIA-3561'>MAGNOLIA-3561</a>.
152      * @version $Id$
153      */
154     protected class RescueUser implements User {
155         private static final long serialVersionUID = 1L;
156 
157         private final String name;
158 
159         private final String password;
160 
161         private final Collection<String> groups = new ArrayList<String>();
162 
163         private final Collection<String> roles = new ArrayList<String>();
164 
165         public RescueUser(String name, String password) {
166             this.name = name;
167             this.password = password;
168 
169             if(UserManager.SYSTEM_USER.equals(name)){
170                 groups.add("publishers");
171 
172                 roles.add("superuser");
173                 roles.add("workflow-base");
174             }
175         }
176 
177         @Override
178         public boolean hasRole(String roleName) {
179             return roles.contains(roleName);
180         }
181 
182         @Override
183         public void removeRole(String roleName) throws UnsupportedOperationException {
184             throw new UnsupportedOperationException();
185         }
186 
187         @Override
188         public void addRole(String roleName) throws UnsupportedOperationException {
189             throw new UnsupportedOperationException();
190         }
191 
192         @Override
193         public boolean inGroup(String groupName) {
194             return groups.contains(groupName);
195         }
196 
197         @Override
198         public void removeGroup(String groupName) throws UnsupportedOperationException {
199             throw new UnsupportedOperationException();
200         }
201 
202         @Override
203         public void addGroup(String groupName) throws UnsupportedOperationException {
204             throw new UnsupportedOperationException();
205         }
206 
207         @Override
208         public boolean isEnabled() {
209             return true;
210         }
211 
212         @Override
213         public void setEnabled(boolean enabled) {
214             throw new UnsupportedOperationException();
215         }
216 
217         @Override
218         public String getLanguage() {
219             return "en";
220         }
221 
222         @Override
223         public String getName() {
224             return name;
225         }
226 
227         @Override
228         public String getPassword() {
229             return password;
230         }
231 
232         @Override
233         public String getProperty(String propertyName) {
234             return null;
235         }
236 
237         @Override
238         public void setProperty(String propertyName, String value) {
239             throw new UnsupportedOperationException();
240         }
241 
242         @Override
243         public String getIdentifier() {
244             throw new UnsupportedOperationException();
245         }
246 
247         @Override
248         public Collection<String> getGroups() {
249             return Collections.unmodifiableCollection(groups);
250         }
251 
252         @Override
253         public Collection<String> getAllGroups() {
254             return Collections.unmodifiableCollection(groups);
255         }
256 
257         @Override
258         public Collection<String> getRoles() {
259             return Collections.unmodifiableCollection(roles);
260         }
261 
262         @Override
263         public Collection<String> getAllRoles() {
264             return Collections.unmodifiableCollection(roles);
265         }
266     }
267 }