/**
*
* 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.yoko.orb.csi;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.security.auth.Subject;
import javax.security.auth.login.LoginException;
import javax.security.auth.x500.X500Principal;
import org.omg.CORBA.Any;
import org.omg.CORBA.CompletionStatus;
import org.omg.CORBA.MARSHAL;
import org.omg.CORBA.OctetSeqHelper;
import org.omg.CORBA.UserException;
import org.omg.CSI.*;
import org.omg.GSSUP.InitialContextToken;
import org.omg.IOP.Codec;
import org.omg.IOP.SecurityAttributeService;
import org.omg.IOP.ServiceContext;
import org.omg.PortableInterceptor.ForwardRequest;
import org.omg.PortableInterceptor.ServerRequestInfo;
import org.omg.Security.DelegationDirective;
import org.omg.Security.RequiresSupports;
import org.omg.Security.SecDelegationDirectivePolicy;
import org.omg.SecurityLevel2.DelegationDirectivePolicy;
import org.apache.yoko.orb.csi.gssup.GSSUPPolicy;
import org.apache.yoko.orb.csi.gssup.SecGSSUPPolicy;
public class CSIServerRequestInterceptor extends CSIInterceptorBase
implements org.omg.PortableInterceptor.ServerRequestInterceptor
{
CSIServerRequestInterceptor(Codec codec) {
super(codec);
}
private static final Logger log = Logger
.getLogger(CSIServerRequestInterceptor.class.getName());
//
// SERVER REQUEST API
//
public void receive_request_service_contexts(ServerRequestInfo ri)
throws ForwardRequest
{
log.fine("receive_request_service_contexts " + ri.operation());
if (CallStatus.peekIsLocal()) {
log.fine("local call");
return;
}
// set null subject so that we won't run in context of some
// previous subject
// CSISubjectInfo.clear ();
boolean support_gssup_authorization = false;
boolean require_gssup_authorization = false;
String gssup_domain = null;
// if there is no GSSUP policy on this POA, then we won't try
// to validate the user.
try {
GSSUPPolicy gp = (GSSUPPolicy) ri
.get_server_policy(SecGSSUPPolicy.value);
if (gp == null) {
log.fine("null GSSUPPolicy");
} else {
support_gssup_authorization = true;
if (gp.mode() == RequiresSupports.SecRequires) {
require_gssup_authorization = true;
}
gssup_domain = gp.domain();
}
}
catch (org.omg.CORBA.INV_POLICY ex) {
log.fine("no GSSUPPolicy");
}
boolean support_gssup_principal_identity = false;
try {
DelegationDirectivePolicy delegate = (DelegationDirectivePolicy) ri
.get_server_policy(SecDelegationDirectivePolicy.value);
if (delegate != null) {
DelegationDirective dir = delegate.delegation_directive();
if (dir == DelegationDirective.Delegate) {
support_gssup_principal_identity = true;
}
}
}
catch (org.omg.CORBA.INV_POLICY ex) {
// ignore //
}
if (log.isLoggable(Level.FINE)) {
log.fine("support gssup authorization: "
+ support_gssup_authorization);
log.fine("require gssup authorization: "
+ require_gssup_authorization);
log.fine("support gssup identity: "
+ support_gssup_principal_identity);
}
ServiceContext serviceContext;
try {
serviceContext = ri
.get_request_service_context(SecurityAttributeService.value);
}
catch (org.omg.CORBA.BAD_PARAM ex) {
serviceContext = null;
}
log.fine("Received request service context: " + serviceContext);
if (require_gssup_authorization && serviceContext == null) {
throw new org.omg.CORBA.NO_PERMISSION(
"GSSUP authorization required"
+ " (missing SAS EstablishContext message)");
}
SASContextBody sasBody = null;
if (serviceContext != null) {
sasBody = decodeSASContextBody(serviceContext);
log.fine("received request of type "
+ sasBody.discriminator());
switch (sasBody.discriminator()) {
case MTCompleteEstablishContext.value:
case MTContextError.value:
// Unexpected
log.severe("Unexpected message of type "
+ sasBody.discriminator());
throw new org.omg.CORBA.NO_PERMISSION("unexpected SAS message");
case MTMessageInContext.value:
log.fine("MTMessageInContext");
throw new org.omg.CORBA.NO_PERMISSION(
"Stateful SAS not supported");
case MTEstablishContext.value:
log.fine("MTEstablishContext");
acceptContext(ri, sasBody.establish_msg(),
support_gssup_authorization,
require_gssup_authorization,
support_gssup_principal_identity, gssup_domain);
break;
}
}
}
public void receive_request(ServerRequestInfo ri) throws ForwardRequest {
}
public void send_reply(ServerRequestInfo ri) {
if (CallStatus.peekIsLocal()) {
return;
}
}
public void send_exception(ServerRequestInfo ri) throws ForwardRequest {
send_reply(ri);
}
public void send_other(ServerRequestInfo ri) throws ForwardRequest {
send_reply(ri);
}
public String name() {
return "CSI Server Interceptor";
}
void acceptContext(ServerRequestInfo ri, EstablishContext establishMsg,
boolean support_gssup_authorization,
boolean require_gssup_authorization,
boolean support_gssup_principal_identity, String gssup_domain)
{
if (establishMsg.client_context_id != 0) {
// Error, we do not support stateful mode
log.severe("Stateful security contexts not supported");
throw new org.omg.CORBA.NO_PERMISSION(
"Stateful security contexts not supported");
}
log.fine("accepting context...");
// Ignore authorization token list (not supported)
// establishMsg.authorization_token;
// Ignore identity token for now
// establishMsg.identity_token;
// Extract client authentication token
if (support_gssup_authorization
&& establishMsg.identity_token.discriminator() == ITTAbsent.value
&& establishMsg.client_authentication_token.length > 0)
{
InitialContextToken gssupToken = decodeGSSUPToken(establishMsg.client_authentication_token);
String useratrealm = utf8decode(gssupToken.username);
String name;
String realm;
int idx = useratrealm.lastIndexOf('@');
if (idx == -1) {
name = useratrealm;
realm = "default";
} else {
name = useratrealm.substring(0, idx);
realm = useratrealm.substring(idx + 1);
}
if (!realm.equals(gssup_domain)) {
returnContextError(ri, 1, 1);
throw new org.omg.CORBA.NO_PERMISSION("bad domain: \"" + realm
+ "\"");
}
String password = utf8decode(gssupToken.password);
log.fine("GSSUP initial context token name=" + name
+ "; realm=" + realm + "; password=" + password);
try {
Subject subject = SecurityContext.login(name, realm, password);
// Login succeeded
SecurityContext.setAuthenticatedSubject(subject);
log.fine("Login succeeded");
returnCompleteEstablishContext(ri);
}
catch (LoginException ex) {
// Login failed
log.log(Level.SEVERE, "Login failed", ex);
returnContextError(ri, 1, 1);
throw new org.omg.CORBA.NO_PERMISSION("login failed");
}
catch (Exception ex) {
log.log(Level.SEVERE, "Exception occured: ", ex);
}
} else if (require_gssup_authorization) {
returnContextError(ri, 1, 1);
throw new org.omg.CORBA.NO_PERMISSION(
"GSSUP authorization required");
} else if (support_gssup_principal_identity
&& establishMsg.identity_token.discriminator() == ITTPrincipalName.value)
{
log.fine("accepting ITTPrincipalName");
byte[] name = establishMsg.identity_token.principal_name();
Any aa;
try {
aa = codec.decode_value(name, OctetSeqHelper.type());
}
catch (UserException e) {
MARSHAL me = new MARSHAL("cannot decode security descriptor",
0, CompletionStatus.COMPLETED_NO);
me.initCause(e);
throw me;
}
byte[] exported_name = OctetSeqHelper.extract(aa);
// byte[] exported_name = uncapsulateByteArray(name);
String userAtDomain = decodeGSSExportedName(exported_name);
log.fine("establish ITTPrincipalName " + userAtDomain);
int idx = userAtDomain.indexOf('@');
String user = "";
String domain;
if (idx == -1) {
user = userAtDomain;
domain = "default";
} else {
user = userAtDomain.substring(0, idx);
domain = userAtDomain.substring(idx + 1);
}
if (gssup_domain != null && !domain.equals(gssup_domain)) {
returnContextError(ri, 1, 1);
log.warning("request designates wrong domain: " + userAtDomain);
throw new org.omg.CORBA.NO_PERMISSION("bad domain");
}
// CSISubjectInfo.setPropagatedCaller (user, domain);
Subject subject = SecurityContext.delegate(user, domain);
SecurityContext.setAuthenticatedSubject(subject);
returnCompleteEstablishContext(ri);
} else if (establishMsg.identity_token.discriminator() == ITTAnonymous.value) {
// establish anoynous identity
log.fine("accepting ITTAnonymous");
// CSISubjectInfo.setAnonymousSubject ();
try {
Subject subject = SecurityContext.anonymousLogin();
SecurityContext.setAuthenticatedSubject(subject);
}
catch (LoginException ex) {
// Won't happen
}
returnCompleteEstablishContext(ri);
} else if (establishMsg.identity_token.discriminator() == ITTDistinguishedName.value) {
log.fine("accepting ITTDistinguishedName");
byte[] name_data = establishMsg.identity_token.dn();
Any aa;
try {
aa = codec.decode_value(name_data, OctetSeqHelper.type());
}
catch (UserException e) {
MARSHAL me = new MARSHAL("cannot encode security descriptor",
0, CompletionStatus.COMPLETED_NO);
me.initCause(e);
throw me;
}
byte[] x500name_data = OctetSeqHelper.extract(aa);
// byte[] x500name_data = uncapsulateByteArray(name_data);
try {
Subject subject = new Subject();
subject.getPrincipals().add(new X500Principal(x500name_data));
SecurityContext.setAuthenticatedSubject(subject);
}
catch (IllegalArgumentException ex) {
log.log(Level.FINE, "cannot decode X500 name", ex);
returnContextError(ri, 1, 1);
throw new org.omg.CORBA.NO_PERMISSION("cannot decode X500 name");
}
returnCompleteEstablishContext(ri);
} else {
returnContextError(ri, 2, 1);
throw new org.omg.CORBA.NO_PERMISSION("Unsupported IdentityToken");
}
}
void returnCompleteEstablishContext(ServerRequestInfo ri) {
// Create CompleteEstablishContext
SASContextBody sasBody = new SASContextBody();
CompleteEstablishContext completeMsg = new CompleteEstablishContext();
completeMsg.client_context_id = 0;
completeMsg.context_stateful = false;
completeMsg.final_context_token = EMPTY_BARR;
sasBody.complete_msg(completeMsg);
log.fine("Adding SASContextBody, discriminator = "
+ sasBody.discriminator());
ri.add_reply_service_context(encodeSASContextBody(sasBody), true);
}
void returnContextError(ServerRequestInfo ri, int major, int minor) {
// Create CompleteEstablishContext
SASContextBody sasBody = new SASContextBody();
ContextError errorMsg = new ContextError();
errorMsg.client_context_id = 0;
errorMsg.major_status = major;
errorMsg.minor_status = minor;
errorMsg.error_token = EMPTY_BARR;
sasBody.error_msg(errorMsg);
log.fine("Adding SASContextBody, discriminator = "
+ sasBody.discriminator());
ri.add_reply_service_context(encodeSASContextBody(sasBody), true);
}
public void destroy() {
// TODO Auto-generated method stub
}
// void login(Subject subject, String realm, String name,
// String password) throws LoginException {
// LoginContext lc = new LoginContext
// ("EASSERVER", subject, new LoginCallbackHandler(name, password));
// lc.login();
// }
}