package org.infinispan.server.endpoint.subsystem; import static org.infinispan.server.endpoint.EndpointLogger.ROOT_LOGGER; import java.io.IOException; import java.security.Principal; import java.util.ArrayList; import java.util.Collection; import java.util.Map; import javax.security.auth.callback.Callback; import javax.security.auth.callback.UnsupportedCallbackException; import javax.security.sasl.AuthorizeCallback; import org.infinispan.server.core.security.AuthorizingCallbackHandler; import org.infinispan.server.core.security.ServerAuthenticationProvider; import org.infinispan.server.core.security.SubjectUserInfo; import org.jboss.as.core.security.RealmUser; import org.jboss.as.domain.management.AuthMechanism; import org.jboss.as.domain.management.RealmConfigurationConstants; import org.jboss.as.domain.management.SecurityRealm; /** * EndpointServerAuthenticationProvider. * * @author Tristan Tarrant * @since 7.0 */ public class EndpointServerAuthenticationProvider implements ServerAuthenticationProvider { static final String SASL_OPT_REALM_PROPERTY = "com.sun.security.sasl.digest.realm"; static final String SASL_OPT_ALT_PROTO_PROPERTY = "org.jboss.sasl.digest.alternative_protocols"; static final String SASL_OPT_PRE_DIGESTED_PROPERTY = "org.jboss.sasl.digest.pre_digested"; static final String DIGEST_MD5 = "DIGEST-MD5"; static final String EXTERNAL = "EXTERNAL"; static final String GSSAPI = "GSSAPI"; static final String PLAIN = "PLAIN"; private final SecurityRealm realm; EndpointServerAuthenticationProvider(SecurityRealm realm) { this.realm = realm; } @Override public AuthorizingCallbackHandler getCallbackHandler(String mechanismName, Map<String, String> mechanismProperties) { if (GSSAPI.equals(mechanismName)) { // The EAP SecurityRealm doesn't actually support a GSSAPI mech yet so let's handle this ourselves return new GSSAPIEndpointAuthorizingCallbackHandler(); } else if (PLAIN.equals(mechanismName)) { return new RealmAuthorizingCallbackHandler(realm.getAuthorizingCallbackHandler(AuthMechanism.PLAIN)); } else if (DIGEST_MD5.equals(mechanismName)) { if (!mechanismProperties.containsKey(SASL_OPT_REALM_PROPERTY)) { mechanismProperties.put(SASL_OPT_REALM_PROPERTY, realm.getName()); } Map<String, String> mechConfig = realm.getMechanismConfig(AuthMechanism.DIGEST); boolean plainTextDigest = true; if (mechConfig.containsKey(RealmConfigurationConstants.DIGEST_PLAIN_TEXT)) { plainTextDigest = Boolean.parseBoolean(mechConfig.get(RealmConfigurationConstants.DIGEST_PLAIN_TEXT)); } if (!plainTextDigest) { mechanismProperties.put(SASL_OPT_PRE_DIGESTED_PROPERTY, "true"); } return new RealmAuthorizingCallbackHandler(realm.getAuthorizingCallbackHandler(AuthMechanism.DIGEST)); } else if (EXTERNAL.equals(mechanismName)) { return new RealmAuthorizingCallbackHandler(realm.getAuthorizingCallbackHandler(AuthMechanism.CLIENT_CERT)); } else { throw new IllegalArgumentException("Unsupported mech " + mechanismName); } } public class GSSAPIEndpointAuthorizingCallbackHandler implements AuthorizingCallbackHandler { private final org.jboss.as.domain.management.AuthorizingCallbackHandler delegate; private RealmUser realmUser; GSSAPIEndpointAuthorizingCallbackHandler() { delegate = realm.getAuthorizingCallbackHandler(AuthMechanism.PLAIN); } @Override public void handle(Callback[] callbacks) throws IOException, UnsupportedCallbackException { AuthorizeCallback acb = (AuthorizeCallback) callbacks[0]; String authenticationId = acb.getAuthenticationID(); String authorizationId = acb.getAuthorizationID(); acb.setAuthorized(authenticationId.equals(authorizationId)); int realmSep = authorizationId.indexOf('@'); realmUser = realmSep <= 0 ? new RealmUser(authorizationId) : new RealmUser(authorizationId.substring(realmSep+1), authorizationId.substring(0, realmSep)); } @Override public SubjectUserInfo getSubjectUserInfo(Collection<Principal> principals) { // The call to the delegate will supplement the realm user with additional role information Collection<Principal> realmPrincipals = new ArrayList<>(); realmPrincipals.add(realmUser); try { org.jboss.as.core.security.SubjectUserInfo userInfo = delegate.createSubjectUserInfo(realmPrincipals); userInfo.getPrincipals().addAll(principals); return new RealmSubjectUserInfo(userInfo); } catch (IOException e) { throw ROOT_LOGGER.cannotRetrieveAuthorizationInformation(e, realmUser.toString()); } } } public class RealmAuthorizingCallbackHandler implements AuthorizingCallbackHandler { private final org.jboss.as.domain.management.AuthorizingCallbackHandler delegate; public RealmAuthorizingCallbackHandler(org.jboss.as.domain.management.AuthorizingCallbackHandler authorizingCallbackHandler) { this.delegate = authorizingCallbackHandler; } @Override public void handle(Callback[] callbacks) throws IOException, UnsupportedCallbackException { delegate.handle(callbacks); } @Override public SubjectUserInfo getSubjectUserInfo(Collection<Principal> principals) { try { org.jboss.as.core.security.SubjectUserInfo realmUserInfo = delegate.createSubjectUserInfo(principals); return new RealmSubjectUserInfo(realmUserInfo.getUserName(), realmUserInfo.getSubject()); } catch (IOException e) { // Handle this return null; } } } }