/** * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ package org.apache.wss4j.stax.impl.securityToken; import java.io.IOException; import java.security.Key; import java.security.Principal; import java.security.PrivilegedActionException; import java.util.Set; import javax.security.auth.Subject; import javax.security.auth.callback.Callback; import javax.security.auth.callback.CallbackHandler; import javax.security.auth.callback.UnsupportedCallbackException; import javax.security.auth.login.LoginContext; import javax.security.auth.login.LoginException; import org.apache.wss4j.common.ext.WSSecurityException; import org.apache.wss4j.common.ext.WSSecurityException.ErrorCode; import org.apache.wss4j.common.kerberos.KerberosContextAndServiceNameCallback; import org.apache.wss4j.common.kerberos.KerberosServiceContext; import org.apache.wss4j.common.kerberos.KerberosServiceExceptionAction; import org.apache.wss4j.common.kerberos.KerberosTokenDecoder; import org.apache.wss4j.common.kerberos.KerberosTokenDecoderException; import org.apache.wss4j.common.util.KeyUtils; import org.apache.wss4j.stax.ext.WSInboundSecurityContext; import org.apache.wss4j.stax.securityToken.KerberosServiceSecurityToken; import org.apache.wss4j.stax.securityToken.WSSecurityTokenConstants; import org.apache.xml.security.exceptions.XMLSecurityException; import org.apache.xml.security.stax.ext.XMLSecurityConstants; import org.apache.xml.security.stax.impl.securityToken.AbstractInboundSecurityToken; public class KerberosServiceSecurityTokenImpl extends AbstractInboundSecurityToken implements KerberosServiceSecurityToken { private CallbackHandler callbackHandler; private byte[] binaryContent; private String kerberosTokenValueType; private KerberosTokenDecoder kerberosTokenDecoder; private Subject subject; private Principal principal; private byte[] sessionKey; public KerberosServiceSecurityTokenImpl(WSInboundSecurityContext wsInboundSecurityContext, CallbackHandler callbackHandler, byte[] binaryContent, String kerberosTokenValueType, String id, WSSecurityTokenConstants.KeyIdentifier keyIdentifier) { super(wsInboundSecurityContext, id, keyIdentifier, true); this.callbackHandler = callbackHandler; this.binaryContent = binaryContent; this.kerberosTokenValueType = kerberosTokenValueType; } @Override public boolean isAsymmetric() throws XMLSecurityException { return false; } @Override public WSSecurityTokenConstants.TokenType getTokenType() { return WSSecurityTokenConstants.KERBEROS_TOKEN; } protected byte[] getTGTSessionKey() throws WSSecurityException { if (sessionKey != null) { return sessionKey; } try { KerberosContextAndServiceNameCallback contextAndServiceNameCallback = new KerberosContextAndServiceNameCallback(); callbackHandler.handle(new Callback[]{contextAndServiceNameCallback}); if (contextAndServiceNameCallback.getContextName() == null) { throw new WSSecurityException(WSSecurityException.ErrorCode.FAILURE, "kerberosCallbackContextNameNotSupplied"); } if (contextAndServiceNameCallback.getServiceName() == null) { throw new WSSecurityException(WSSecurityException.ErrorCode.FAILURE, "kerberosCallbackServiceNameNotSupplied"); } LoginContext loginContext = new LoginContext(contextAndServiceNameCallback.getContextName(), callbackHandler); loginContext.login(); // Get the service name to use - fall back on the principal this.subject = loginContext.getSubject(); String service = contextAndServiceNameCallback.getServiceName(); if (service == null) { Set<Principal> principals = subject.getPrincipals(); if (principals.isEmpty()) { throw new WSSecurityException( WSSecurityException.ErrorCode.FAILURE, "kerberosLoginError", new Object[] {"No Client principals found after login"} ); } service = principals.iterator().next().getName(); } KerberosServiceExceptionAction action = new KerberosServiceExceptionAction(binaryContent, service, contextAndServiceNameCallback.isUsernameServiceNameForm(), false); KerberosServiceContext krbServiceCtx = null; try { krbServiceCtx = Subject.doAs(subject, action); } catch (PrivilegedActionException e) { Throwable cause = e.getCause(); if (cause instanceof WSSecurityException) { throw (WSSecurityException) cause; } else { throw new WSSecurityException( ErrorCode.FAILURE, new Exception(cause), "kerberosTicketValidationError" ); } } this.principal = krbServiceCtx.getPrincipal(); Key key = krbServiceCtx.getSessionKey(); if (key != null) { sessionKey = key.getEncoded(); } else if (kerberosTokenDecoder != null) { kerberosTokenDecoder.clear(); kerberosTokenDecoder.setToken(binaryContent); kerberosTokenDecoder.setSubject(subject); sessionKey = kerberosTokenDecoder.getSessionKey(); } return sessionKey; } catch (LoginException | UnsupportedCallbackException | IOException e) { throw new WSSecurityException(WSSecurityException.ErrorCode.FAILURE, e); } catch (KerberosTokenDecoderException e) { throw new WSSecurityException(WSSecurityException.ErrorCode.INVALID_SECURITY_TOKEN, e); } } @Override protected Key getKey(String algorithmURI, XMLSecurityConstants.AlgorithmUsage algorithmUsage, String correlationID) throws XMLSecurityException { Key key = getSecretKey().get(algorithmURI); if (key != null) { return key; } byte[] sk = getTGTSessionKey(); key = KeyUtils.prepareSecretKey(algorithmURI, sk); setSecretKey(algorithmURI, key); return key; } public byte[] getBinaryContent() { return binaryContent; } public String getKerberosTokenValueType() { return kerberosTokenValueType; } @Override public Subject getSubject() throws WSSecurityException { return subject; } @Override public Principal getPrincipal() throws WSSecurityException { return principal; } /** * Get the KerberosTokenDecoder instance used to extract a session key from the received Kerberos * token. * @return the KerberosTokenDecoder instance used to extract a session key */ public KerberosTokenDecoder getKerberosTokenDecoder() { return kerberosTokenDecoder; } /** * Set the KerberosTokenDecoder instance used to extract a session key from the received Kerberos * token. * @param kerberosTokenDecoder the KerberosTokenDecoder instance used to extract a session key */ public void setKerberosTokenDecoder(KerberosTokenDecoder kerberosTokenDecoder) { this.kerberosTokenDecoder = kerberosTokenDecoder; } }