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

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

Return to bug 64715