View | Details | Raw Unified | Return to bug 64715
Collapse All | Expand All

(-)a/java/org/apache/catalina/authenticator/AuthenticatorBase.java (-23 / +32 lines)
Lines 42-47 Link Here
42
import javax.servlet.http.HttpServletResponse;
42
import javax.servlet.http.HttpServletResponse;
43
43
44
import org.apache.catalina.Authenticator;
44
import org.apache.catalina.Authenticator;
45
import org.apache.catalina.Contained;
45
import org.apache.catalina.Container;
46
import org.apache.catalina.Container;
46
import org.apache.catalina.Context;
47
import org.apache.catalina.Context;
47
import org.apache.catalina.Globals;
48
import org.apache.catalina.Globals;
Lines 50-56 Link Here
50
import org.apache.catalina.Session;
51
import org.apache.catalina.Session;
51
import org.apache.catalina.TomcatPrincipal;
52
import org.apache.catalina.TomcatPrincipal;
52
import org.apache.catalina.Valve;
53
import org.apache.catalina.Valve;
53
import org.apache.catalina.authenticator.jaspic.CallbackHandlerImpl;
54
import org.apache.catalina.authenticator.jaspic.MessageInfoImpl;
54
import org.apache.catalina.authenticator.jaspic.MessageInfoImpl;
55
import org.apache.catalina.connector.Request;
55
import org.apache.catalina.connector.Request;
56
import org.apache.catalina.connector.Response;
56
import org.apache.catalina.connector.Response;
Lines 219-225 Link Here
219
     * default {@link org.apache.catalina.authenticator.jaspic.CallbackHandlerImpl}
219
     * default {@link org.apache.catalina.authenticator.jaspic.CallbackHandlerImpl}
220
     * will be used.
220
     * will be used.
221
     */
221
     */
222
    protected String jaspicCallbackHandlerClass = null;
222
    protected String jaspicCallbackHandlerClass = "org.apache.catalina.authenticator.jaspic.CallbackHandlerImpl";
223
223
224
    /**
224
    /**
225
     * Should the auth information (remote user and auth type) be returned as response
225
     * Should the auth information (remote user and auth type) be returned as response
Lines 246-251 Link Here
246
246
247
    private volatile String jaspicAppContextID = null;
247
    private volatile String jaspicAppContextID = null;
248
    private volatile Optional<AuthConfigProvider> jaspicProvider = null;
248
    private volatile Optional<AuthConfigProvider> jaspicProvider = null;
249
    private volatile CallbackHandler jaspicCallbackHandler = null;
249
250
250
251
251
    // ------------------------------------------------------------- Properties
252
    // ------------------------------------------------------------- Properties
Lines 772-778 Link Here
772
                new MessageInfoImpl(request.getRequest(), response.getResponse(), authMandatory);
773
                new MessageInfoImpl(request.getRequest(), response.getResponse(), authMandatory);
773
774
774
        try {
775
        try {
775
            CallbackHandler callbackHandler = createCallbackHandler();
776
            CallbackHandler callbackHandler = getCallbackHandler();
776
            ServerAuthConfig serverAuthConfig = jaspicProvider.getServerAuthConfig(
777
            ServerAuthConfig serverAuthConfig = jaspicProvider.getServerAuthConfig(
777
                    "HttpServlet", jaspicAppContextID, callbackHandler);
778
                    "HttpServlet", jaspicAppContextID, callbackHandler);
778
            String authContextID = serverAuthConfig.getAuthContextID(jaspicState.messageInfo);
779
            String authContextID = serverAuthConfig.getAuthContextID(jaspicState.messageInfo);
Lines 786-814 Link Here
786
        return jaspicState;
787
        return jaspicState;
787
    }
788
    }
788
789
790
    private CallbackHandler getCallbackHandler() {
791
        CallbackHandler handler = jaspicCallbackHandler;
792
        if (handler == null) {
793
            handler = createCallbackHandler();
794
        }
795
        return handler;
796
    }
797
    
789
    private CallbackHandler createCallbackHandler() {
798
    private CallbackHandler createCallbackHandler() {
790
        CallbackHandler callbackHandler = null;
799
        CallbackHandler callbackHandler = null;
791
        if (jaspicCallbackHandlerClass == null) {
800
        Class<?> clazz = null;
792
            callbackHandler = CallbackHandlerImpl.getInstance();
801
        try {
793
        } else {
802
            clazz = Class.forName(jaspicCallbackHandlerClass, true,
794
            Class<?> clazz = null;
803
                    Thread.currentThread().getContextClassLoader());
795
            try {
804
        } catch (ClassNotFoundException e) {
796
                clazz = Class.forName(jaspicCallbackHandlerClass, true,
805
            // Proceed with the retry below
797
                        Thread.currentThread().getContextClassLoader());
798
            } catch (ClassNotFoundException e) {
799
                // Proceed with the retry below
800
            }
801
802
            try {
803
                if (clazz == null) {
804
                    clazz = Class.forName(jaspicCallbackHandlerClass);
805
                }
806
                callbackHandler = (CallbackHandler)clazz.getConstructor().newInstance();
807
            } catch (ReflectiveOperationException e) {
808
                throw new SecurityException(e);
809
            }
810
        }
806
        }
811
807
808
        try {
809
            if (clazz == null) {
810
                clazz = Class.forName(jaspicCallbackHandlerClass);
811
            }
812
            callbackHandler = (CallbackHandler) clazz.getConstructor().newInstance();
813
            if (callbackHandler instanceof Contained) {
814
                ((Contained)callbackHandler).setContainer(context);
815
            }
816
        } catch (ReflectiveOperationException e) {
817
            throw new SecurityException(e);
818
        }
819
820
        jaspicCallbackHandler = callbackHandler;
812
        return callbackHandler;
821
        return callbackHandler;
813
    }
822
    }
814
823
Lines 1304-1310 Link Here
1304
                ServerAuthContext serverAuthContext;
1313
                ServerAuthContext serverAuthContext;
1305
                try {
1314
                try {
1306
                    ServerAuthConfig serverAuthConfig = provider.getServerAuthConfig("HttpServlet",
1315
                    ServerAuthConfig serverAuthConfig = provider.getServerAuthConfig("HttpServlet",
1307
                            jaspicAppContextID, CallbackHandlerImpl.getInstance());
1316
                            jaspicAppContextID, getCallbackHandler());
1308
                    String authContextID = serverAuthConfig.getAuthContextID(messageInfo);
1317
                    String authContextID = serverAuthConfig.getAuthContextID(messageInfo);
1309
                    serverAuthContext = serverAuthConfig.getAuthContext(authContextID, null, null);
1318
                    serverAuthContext = serverAuthConfig.getAuthContext(authContextID, null, null);
1310
                    serverAuthContext.cleanSubject(messageInfo, client);
1319
                    serverAuthContext.cleanSubject(messageInfo, client);
(-)a/java/org/apache/catalina/authenticator/jaspic/CallbackHandlerImpl.java (-23 / +37 lines)
Lines 28-63 Link Here
28
import javax.security.auth.callback.UnsupportedCallbackException;
28
import javax.security.auth.callback.UnsupportedCallbackException;
29
import javax.security.auth.message.callback.CallerPrincipalCallback;
29
import javax.security.auth.message.callback.CallerPrincipalCallback;
30
import javax.security.auth.message.callback.GroupPrincipalCallback;
30
import javax.security.auth.message.callback.GroupPrincipalCallback;
31
import javax.security.auth.message.callback.PasswordValidationCallback;
31
32
33
import org.apache.catalina.Contained;
34
import org.apache.catalina.Container;
35
import org.apache.catalina.authenticator.AuthenticatorBase;
32
import org.apache.catalina.realm.GenericPrincipal;
36
import org.apache.catalina.realm.GenericPrincipal;
33
import org.apache.juli.logging.Log;
37
import org.apache.juli.logging.Log;
34
import org.apache.juli.logging.LogFactory;
38
import org.apache.juli.logging.LogFactory;
35
import org.apache.tomcat.util.res.StringManager;
39
import org.apache.tomcat.util.res.StringManager;
36
40
37
/**
41
/**
38
 * Implemented as a singleton since the class is stateless.
42
 * Default implementation of a JASPIC CallbackHandler.
43
 * 
44
 * @see AuthenticatorBase#setJaspicCallbackHandlerClass(String)
39
 */
45
 */
40
public class CallbackHandlerImpl implements CallbackHandler {
46
public class CallbackHandlerImpl implements CallbackHandler, Contained {
41
47
42
    private static final StringManager sm = StringManager.getManager(CallbackHandlerImpl.class);
48
    private final Log log = LogFactory.getLog(CallbackHandlerImpl.class); // must not be static
49
    
50
    protected static final StringManager sm = StringManager.getManager(CallbackHandlerImpl.class);
43
51
44
    private static CallbackHandler instance;
52
    protected Container container;
45
46
47
    static {
48
        instance = new CallbackHandlerImpl();
49
    }
50
51
52
    public static CallbackHandler getInstance() {
53
        return instance;
54
    }
55
56
57
    private  CallbackHandlerImpl() {
58
        // Hide default constructor
59
    }
60
61
53
62
    @Override
54
    @Override
63
    public void handle(Callback[] callbacks) throws IOException, UnsupportedCallbackException {
55
    public void handle(Callback[] callbacks) throws IOException, UnsupportedCallbackException {
Lines 80-89 Link Here
80
                } else if (callback instanceof GroupPrincipalCallback) {
72
                } else if (callback instanceof GroupPrincipalCallback) {
81
                    GroupPrincipalCallback gpc = (GroupPrincipalCallback) callback;
73
                    GroupPrincipalCallback gpc = (GroupPrincipalCallback) callback;
82
                    groups = gpc.getGroups();
74
                    groups = gpc.getGroups();
75
                } else if (callback instanceof PasswordValidationCallback) {
76
                    if (container == null) {
77
                        log.warn(sm.getString("callbackHandlerImpl.containerMissing",
78
                                callback.getClass().getName()));
79
                    } else if (container.getRealm() == null) {
80
                        log.warn(sm.getString("callbackHandlerImpl.realmMissing",
81
                                callback.getClass().getName(), container.getName()));
82
                    } else {
83
                        PasswordValidationCallback pvc = (PasswordValidationCallback) callback;
84
                        principal = container.getRealm().authenticate(pvc.getUsername(),
85
                                String.valueOf(pvc.getPassword()));
86
                        subject = pvc.getSubject();
87
                    }
83
                } else {
88
                } else {
84
                    // This is a singleton so need to get correct Logger for
85
                    // current TCCL
86
                    Log log = LogFactory.getLog(CallbackHandlerImpl.class);
87
                    log.error(sm.getString("callbackHandlerImpl.jaspicCallbackMissing",
89
                    log.error(sm.getString("callbackHandlerImpl.jaspicCallbackMissing",
88
                            callback.getClass().getName()));
90
                            callback.getClass().getName()));
89
                }
91
                }
Lines 118-121 Link Here
118
120
119
        return new GenericPrincipal(name, null, roles, principal);
121
        return new GenericPrincipal(name, null, roles, principal);
120
    }
122
    }
123
124
125
    @Override
126
    public Container getContainer() {
127
        return this.container;
128
    }
129
130
131
    @Override
132
    public void setContainer(Container container) {
133
        this.container = container;
134
    }
121
}
135
}
(-)a/java/org/apache/catalina/authenticator/jaspic/LocalStrings.properties (+2 lines)
Lines 20-25 Link Here
20
authConfigFactoryImpl.zeroLengthMessageLayer=A zero length message layer name is not valid
20
authConfigFactoryImpl.zeroLengthMessageLayer=A zero length message layer name is not valid
21
21
22
callbackHandlerImpl.jaspicCallbackMissing=Unsupported JASPIC callback of type [{0}] received which was ignored
22
callbackHandlerImpl.jaspicCallbackMissing=Unsupported JASPIC callback of type [{0}] received which was ignored
23
callbackHandlerImpl.realmMissing=Missing realm for JASPIC callback of type [{0}] in container [{1}] which was ignored
24
callbackHandlerImpl.containerMissing=Missing container for JASPIC callback of type [{0}] which was ignored
23
25
24
jaspicAuthenticator.authenticate=Authenticating request for [{0}] via JASPIC
26
jaspicAuthenticator.authenticate=Authenticating request for [{0}] via JASPIC
25
27
(-)a/test/org/apache/catalina/authenticator/TestJaspicCallbackHandlerInAuthenticator.java (-11 / +109 lines)
Lines 19-35 Link Here
19
import java.io.IOException;
19
import java.io.IOException;
20
import java.lang.reflect.InvocationTargetException;
20
import java.lang.reflect.InvocationTargetException;
21
import java.lang.reflect.Method;
21
import java.lang.reflect.Method;
22
import java.security.Principal;
23
import java.util.Arrays;
24
import java.util.HashSet;
25
import java.util.Set;
22
26
27
import javax.security.auth.Subject;
23
import javax.security.auth.callback.Callback;
28
import javax.security.auth.callback.Callback;
24
import javax.security.auth.callback.CallbackHandler;
29
import javax.security.auth.callback.CallbackHandler;
25
import javax.security.auth.callback.UnsupportedCallbackException;
30
import javax.security.auth.callback.UnsupportedCallbackException;
31
import javax.security.auth.message.callback.CallerPrincipalCallback;
32
import javax.security.auth.message.callback.GroupPrincipalCallback;
33
import javax.security.auth.message.callback.PasswordValidationCallback;
26
import javax.servlet.http.HttpServletResponse;
34
import javax.servlet.http.HttpServletResponse;
27
35
28
import org.junit.Assert;
36
import org.apache.catalina.Contained;
29
import org.junit.Test;
37
import org.apache.catalina.Container;
30
31
import org.apache.catalina.authenticator.jaspic.CallbackHandlerImpl;
38
import org.apache.catalina.authenticator.jaspic.CallbackHandlerImpl;
32
import org.apache.catalina.connector.Request;
39
import org.apache.catalina.connector.Request;
40
import org.apache.catalina.core.ContainerBase;
41
import org.apache.catalina.realm.GenericPrincipal;
42
import org.apache.catalina.realm.RealmBase;
43
import org.junit.Assert;
44
import org.junit.Test;
33
45
34
public class TestJaspicCallbackHandlerInAuthenticator {
46
public class TestJaspicCallbackHandlerInAuthenticator {
35
47
Lines 44-62 Link Here
44
        testCallbackHandlerCreation(null, CallbackHandlerImpl.class);
56
        testCallbackHandlerCreation(null, CallbackHandlerImpl.class);
45
    }
57
    }
46
58
59
    @Test
60
    public void testCallerPrincipalCallback() throws Exception {
61
        CallbackHandler callbackHandler = createCallbackHandler(null);
62
        Subject clientSubject = new Subject();
63
        CallerPrincipalCallback cpc1 = new CallerPrincipalCallback(clientSubject, "name1");
64
        callbackHandler.handle(new Callback[] { cpc1 });
65
        CallerPrincipalCallback cpc2 = new CallerPrincipalCallback(clientSubject, new Principal() {
66
            @Override
67
            public String getName() {
68
                return "name2";
69
            }
70
        });
71
        callbackHandler.handle(new Callback[] { cpc2 });
72
        Set<Object> credentials = clientSubject.getPrivateCredentials();
73
        Assert.assertTrue(credentials.size() == 2);
74
        Set<String> names = new HashSet<String>(Arrays.asList(new String[] { "name1", "name2" }));
75
        for (Object o : credentials)
76
            names.remove(((GenericPrincipal) o).getName());
77
        Assert.assertTrue(names.isEmpty());
78
    }
79
80
    @Test
81
    public void testGroupPrincipalCallback() throws Exception {
82
        CallbackHandler callbackHandler = createCallbackHandler(null);
83
        Subject clientSubject = new Subject();
84
        CallerPrincipalCallback cpc = new CallerPrincipalCallback(clientSubject, "name");
85
        GroupPrincipalCallback gpc = new GroupPrincipalCallback(clientSubject,
86
                new String[] { "group1", "group2" });
87
        callbackHandler.handle(new Callback[] { cpc, gpc });
88
        Set<Object> credentials = clientSubject.getPrivateCredentials();
89
        Assert.assertTrue(credentials.size() == 1);
90
        GenericPrincipal gp = (GenericPrincipal) credentials.iterator().next();
91
        Assert.assertEquals("name", gp.getName());
92
        Assert.assertTrue(gp.hasRole("group1"));
93
        Assert.assertTrue(gp.hasRole("group2"));
94
    }
95
96
    @Test
97
    public void testPasswordValidationCallback() throws Exception {
98
        CallbackHandler callbackHandler = createCallbackHandler(null);
99
        Container container = new TestContainer();
100
        container.setRealm(new TestRealm());
101
        ((Contained) callbackHandler).setContainer(container);
102
        Subject clientSubject = new Subject();
103
        PasswordValidationCallback pvc1 = new PasswordValidationCallback(clientSubject, "name1",
104
                "password".toCharArray());
105
        callbackHandler.handle(new Callback[] { pvc1 });
106
        PasswordValidationCallback pvc2 = new PasswordValidationCallback(clientSubject, "name2",
107
                "invalid".toCharArray());
108
        callbackHandler.handle(new Callback[] { pvc2 });
109
        Set<Object> credentials = clientSubject.getPrivateCredentials();
110
        Assert.assertTrue(credentials.size() == 1);
111
        GenericPrincipal gp = (GenericPrincipal) credentials.iterator().next();
112
        Assert.assertEquals("name1", gp.getName());
113
    }
47
114
48
    private void testCallbackHandlerCreation(String callbackHandlerImplClassName,
115
    private void testCallbackHandlerCreation(String callbackHandlerImplClassName,
49
            Class<?> callbackHandlerImplClass)
116
            Class<?> callbackHandlerImplClass) throws NoSuchMethodException, SecurityException,
117
            IllegalAccessException, IllegalArgumentException, InvocationTargetException {
118
        CallbackHandler callbackHandler = createCallbackHandler(callbackHandlerImplClassName);
119
        Assert.assertTrue(callbackHandlerImplClass.isInstance(callbackHandler));
120
    }
121
122
    private CallbackHandler createCallbackHandler(String callbackHandlerImplClassName)
50
            throws NoSuchMethodException, SecurityException, IllegalAccessException,
123
            throws NoSuchMethodException, SecurityException, IllegalAccessException,
51
            IllegalArgumentException, InvocationTargetException {
124
            IllegalArgumentException, InvocationTargetException {
52
        TestAuthenticator authenticator = new TestAuthenticator();
125
        TestAuthenticator authenticator = new TestAuthenticator();
53
        authenticator.setJaspicCallbackHandlerClass(callbackHandlerImplClassName);
126
        if (callbackHandlerImplClassName != null)
54
        Method createCallbackHandlerMethod =
127
            authenticator.setJaspicCallbackHandlerClass(callbackHandlerImplClassName);
55
                AuthenticatorBase.class.getDeclaredMethod("createCallbackHandler");
128
        Method createCallbackHandlerMethod = AuthenticatorBase.class
129
                .getDeclaredMethod("createCallbackHandler");
56
        createCallbackHandlerMethod.setAccessible(true);
130
        createCallbackHandlerMethod.setAccessible(true);
57
        CallbackHandler callbackHandler =
131
        return (CallbackHandler) createCallbackHandlerMethod.invoke(authenticator);
58
                (CallbackHandler) createCallbackHandlerMethod.invoke(authenticator);
59
        Assert.assertTrue(callbackHandlerImplClass.isInstance(callbackHandler));
60
    }
132
    }
61
133
62
    private static class TestAuthenticator extends AuthenticatorBase {
134
    private static class TestAuthenticator extends AuthenticatorBase {
Lines 71-77 Link Here
71
        protected String getAuthMethod() {
143
        protected String getAuthMethod() {
72
            return null;
144
            return null;
73
        }
145
        }
146
    }
74
147
148
    private static class TestContainer extends ContainerBase {
149
150
        @Override
151
        protected String getObjectNameKeyProperties() {
152
            return null;
153
        }
154
    }
155
156
    private static class TestRealm extends RealmBase {
157
158
        @Override
159
        public Principal authenticate(String username, String password) {
160
            if (getPassword(username).equals(password))
161
                return getPrincipal(username);
162
            return null;
163
        }
164
165
        @Override
166
        protected String getPassword(String username) {
167
            return "password";
168
        }
169
170
        @Override
171
        protected Principal getPrincipal(String username) {
172
            return new GenericPrincipal(username, null, null);
173
        }
75
    }
174
    }
76
}
175
}
77
176
Lines 81-87 Link Here
81
        // Default constructor required by reflection
180
        // Default constructor required by reflection
82
    }
181
    }
83
182
84
85
    @Override
183
    @Override
86
    public void handle(Callback[] callbacks) throws IOException, UnsupportedCallbackException {
184
    public void handle(Callback[] callbacks) throws IOException, UnsupportedCallbackException {
87
        // don't have to do anything; needed only for instantiation
185
        // don't have to do anything; needed only for instantiation

Return to bug 64715