PageRenderTime 41ms CodeModel.GetById 1ms app.highlight 36ms RepoModel.GetById 1ms app.codeStats 0ms

/AuthenticRoast/AuthenticRoast-Impl/src/main/java/name/aikesommer/authenticator/TomcatAuthenticator.java

http://authenticroast.googlecode.com/
Java | 287 lines | 220 code | 38 blank | 29 comment | 35 complexity | 0fef8802bfbe3a4b0c39637f32a551c9 MD5 | raw file
  1/**
  2 *    Copyright (C) 2007-2010 Aike J Sommer (http://aikesommer.name/)
  3 *
  4 *    This file is part of AuthenticRoast.
  5 *
  6 *    This library is free software; you can redistribute it and/or
  7 *    modify it under the terms of the GNU Lesser General Public
  8 *    License as published by the Free Software Foundation; either
  9 *    version 3 of the License, or (at your option) any later version.
 10 *
 11 *    This library is distributed in the hope that it will be useful,
 12 *    but WITHOUT ANY WARRANTY; without even the implied warranty of
 13 *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 14 *    Lesser General Public License for more details.
 15 *
 16 *    You should have received a copy of the GNU Lesser General
 17 *    Public License along with this library; if not, write to the
 18 *    Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
 19 *    Boston, MA 02110-1301 USA
 20 *
 21 *    You can reach the author and get more information about this
 22 *    project at: http://aikesommer.name/
 23 */
 24package name.aikesommer.authenticator;
 25
 26import java.io.IOException;
 27import java.lang.reflect.Field;
 28import java.security.Principal;
 29import java.util.LinkedList;
 30import javax.servlet.ServletContext;
 31import javax.servlet.ServletException;
 32import org.apache.catalina.Authenticator;
 33import org.apache.catalina.Container;
 34import org.apache.catalina.Context;
 35import org.apache.catalina.Realm;
 36import org.apache.catalina.Session;
 37import org.apache.catalina.authenticator.Constants;
 38import org.apache.catalina.connector.Request;
 39import org.apache.catalina.connector.Response;
 40import org.apache.catalina.core.ApplicationContext;
 41import org.apache.catalina.core.StandardContext;
 42import org.apache.catalina.deploy.SecurityConstraint;
 43import org.apache.catalina.realm.GenericPrincipal;
 44import org.apache.catalina.valves.ValveBase;
 45
 46
 47/**
 48 * This is the main class called by the container. You probably dont wanna
 49 * call this class directly.
 50 * 
 51 * @author Aike J Sommer
 52 */
 53public class TomcatAuthenticator extends ValveBase implements Authenticator {
 54
 55    static {
 56        RegistryImpl.setResolver(new ClassLoaderResolver() {
 57
 58            public ClassLoader resolve(ServletContext context) {
 59                try {
 60                    Field appContextField =
 61                            context.getClass().getDeclaredField("context");
 62                    appContextField.setAccessible(true);
 63                    ApplicationContext appContext =
 64                            (ApplicationContext) appContextField.get(context);
 65                    appContextField.setAccessible(false);
 66                    Field stdContextField = appContext.getClass().
 67                            getDeclaredField("context");
 68                    stdContextField.setAccessible(true);
 69                    StandardContext stdContext =
 70                            (StandardContext) stdContextField.get(appContext);
 71                    appContextField.setAccessible(false);
 72                    return stdContext.getLoader().getClassLoader();
 73                } catch (Exception ex) {
 74                    throw new RuntimeException(ex);
 75                }
 76            }
 77
 78        });
 79    }
 80
 81    private Context context;
 82
 83    private AuthenticationManagerBase manager = new AuthenticationManagerBase() {
 84
 85        @Override
 86        public void register(AuthenticationRequest request, SimplePrincipal simplePrincipal) {
 87            TomcatAuthenticator.this.register(request, simplePrincipal);
 88            super.register(request, simplePrincipal);
 89        }
 90
 91    };
 92
 93    protected void register(AuthenticationRequest request,
 94            SimplePrincipal simplePrincipal) {
 95        try {
 96            Tomcat6Request req =
 97                    (Tomcat6Request) request;
 98            GenericPrincipal gp = new GenericPrincipal(context.getRealm(),
 99                    simplePrincipal.getName(), null,
100                    new LinkedList<String>(simplePrincipal.getGroups()),
101                    simplePrincipal);
102            req.getCatalinaRequest().setAuthType("ROAST");
103            req.getCatalinaRequest().setUserPrincipal(gp);
104            Session session = req.getCatalinaRequest().getSessionInternal(true);
105            session.setAuthType("ROAST");
106            session.setPrincipal(gp);
107            session.setNote(Constants.SESS_USERNAME_NOTE, simplePrincipal.getName());
108        } catch (Exception ex) {
109            throw new RuntimeException(ex);
110        }
111    }
112
113    @Override
114    public void setContainer(Container container) {
115        this.context = (Context) container;
116        super.setContainer(container);
117    }
118
119    private boolean hasAuthConstraint(SecurityConstraint[] constraints) {
120        if (constraints == null) {
121            return false;
122        }
123
124        for (int i = 0; i < constraints.length; i++) {
125            SecurityConstraint constraint = constraints[i];
126            if (! constraint.getAuthConstraint()) {
127                continue;
128            }
129
130            return true;
131        }
132
133        return false;
134    }
135
136    private boolean checkRoles(Request request, Response response,
137            SecurityConstraint[] constraints, Principal principal) {
138        if (constraints == null) {
139            return true;
140        }
141
142        for (int i = 0; i < constraints.length; i++) {
143            SecurityConstraint constraint = constraints[i];
144            if (! constraint.getAuthConstraint()) {
145                continue;
146            }
147
148            String[] roles = constraint.getAllRoles() ? context.findSecurityRoles()
149                    : constraint.findAuthRoles();
150            if (roles == null) {
151                roles = new String[0];
152            }
153
154            boolean match = false;
155            for (int j = 0; j < roles.length; j++) {
156                String role = roles[j];
157                if (checkRole(principal, role)) {
158                    match = true;
159                    break;
160                }
161            }
162            
163            if (! match) {
164                response.setStatus(Response.SC_FORBIDDEN);
165                return false;
166            }
167        }
168
169        return true;
170    }
171
172    private boolean checkRole(Principal principal, String role) {
173        if (principal instanceof SimplePrincipal) {
174            return ((SimplePrincipal) principal).getGroups().contains(role);
175        } else if (principal instanceof GenericPrincipal) {
176            for (int i = 0; i < ((GenericPrincipal) principal).getRoles().length; i++) {
177                String hasRole = ((GenericPrincipal) principal).getRoles()[i];
178                if (hasRole.equals(role)) {
179                    return true;
180                }
181            }
182        }
183
184        return false;
185    }
186
187    @Override
188    public void invoke(Request request, Response response) throws IOException, ServletException {
189        if (null == request.getCharacterEncoding()) {
190            request.setCharacterEncoding("UTF-8");
191        }
192
193        Realm realm = context.getRealm();
194        SecurityConstraint[] constraints =
195                realm.findSecurityConstraints(request, this.context);
196
197        RegistryImpl registry = RegistryImpl.forContext(request.getContext().
198                getServletContext());
199        if (!realm.hasUserDataPermission(request, response,
200                constraints)) {
201            return;
202        }
203
204        boolean hasAuthConstraint = hasAuthConstraint(constraints);
205        Tomcat6Request authReq =
206                new AuthenticationRequestImpl.Tomcat6(request, response,
207                hasAuthConstraint, registry.isCrossContext());
208        registry.createPrincipalStore(authReq);
209
210        PluggableAuthenticator authenticator = registry.authenticator();
211
212        if (authenticator == null) {
213            if (! hasAuthConstraint) {
214                getNext().invoke(request, response);
215                return;
216            } else {
217                response.setStatus(Response.SC_FORBIDDEN);
218                return;
219            }
220        }
221
222        authenticator.begin(manager, authReq);
223
224        boolean finished = false;
225        try {
226            SimplePrincipal simplePrincipal = registry.principalStore().fetch();
227            if (simplePrincipal != null) {
228                AuthenticationRequest.ManageAction action = authenticator.manage(manager, authReq);
229                switch (action) {
230                    case None:
231                        register(authReq, simplePrincipal);
232
233                        if (!checkRoles(request, response, constraints,
234                                simplePrincipal)) {
235                            return;
236                        }
237
238                        authenticator.finish(manager, authReq);
239                        finished = true;
240                        getNext().invoke(request, response);
241                        return;
242                    case Clear:
243                        registry.principalStore().invalidate();
244                        if (authReq.isForwarded()) {
245                            return;
246                        }
247                }
248            }
249
250            switch (authenticator.tryAuthenticate(manager, authReq)) {
251                case Continue:
252                    return;
253                case Failure:
254                    response.setStatus(Response.SC_FORBIDDEN);
255                    return;
256                case None:
257                    if (hasAuthConstraint) {
258                        switch (authenticator.authenticate(manager, authReq)) {
259                            case Continue:
260                                return;
261                            case Success:
262                                break;
263                            default:
264                                response.setStatus(Response.SC_FORBIDDEN);
265                                return;
266                        }
267                    }
268            }
269
270            simplePrincipal = registry.principalStore().fetch();
271            if (!checkRoles(request, response, constraints, simplePrincipal)) {
272                return;
273            }
274        } catch (Throwable t) {
275            finished = true;
276            authenticator.abort(manager, authReq, t);
277            throw new RuntimeException(t);
278        } finally {
279            if (!finished) {
280                authenticator.finish(manager, authReq);
281            }
282        }
283
284        getNext().invoke(request, response);
285    }
286
287}