001/*
002 * Copyright (c) 2006-2011 Nuxeo SA (http://nuxeo.com/) and others.
003 *
004 * All rights reserved. This program and the accompanying materials
005 * are made available under the terms of the Eclipse Public License v1.0
006 * which accompanies this distribution, and is available at
007 * http://www.eclipse.org/legal/epl-v10.html
008 *
009 * Contributors:
010 *     Nuxeo - initial API and implementation
011 *
012 * $Id$
013 */
014
015package org.nuxeo.runtime.api.login;
016
017import java.io.IOException;
018import java.io.ObjectInputStream;
019import java.io.ObjectOutputStream;
020import java.io.Serializable;
021import java.util.ArrayList;
022import java.util.HashMap;
023import java.util.List;
024import java.util.Map;
025
026import javax.security.auth.Subject;
027import javax.security.auth.callback.CallbackHandler;
028import javax.security.auth.login.AppConfigurationEntry;
029import javax.security.auth.login.LoginContext;
030import javax.security.auth.login.LoginException;
031import javax.security.auth.login.AppConfigurationEntry.LoginModuleControlFlag;
032
033import org.nuxeo.common.xmap.annotation.XNode;
034import org.nuxeo.common.xmap.annotation.XNodeList;
035import org.nuxeo.common.xmap.annotation.XObject;
036import org.nuxeo.runtime.api.LoginModuleWrapper;
037
038/**
039 * @author <a href="mailto:bs@nuxeo.com">Bogdan Stefanescu</a>
040 */
041@XObject("domain")
042public class SecurityDomain implements Serializable {
043
044    private static final long serialVersionUID = 5770889355854831093L;
045
046    @XNode("@name")
047    private String name;
048
049    private transient AppConfigurationEntry[] entries;
050
051    public SecurityDomain() {
052    }
053
054    public SecurityDomain(String name) {
055        this.name = name;
056    }
057
058    public SecurityDomain(String name, AppConfigurationEntry[] entries) {
059        this.name = name;
060        this.entries = entries;
061    }
062
063    public String getName() {
064        return name;
065    }
066
067    public AppConfigurationEntry[] getAppConfigurationEntries() {
068        return entries;
069    }
070
071    public void setAppConfigurationEntries(AppConfigurationEntry[] entries) {
072        this.entries = entries;
073    }
074
075    @XNodeList(value = "login-module", type = ArrayList.class, componentType = LoginModuleDescriptor.class)
076    public void setEntries(List<LoginModuleDescriptor> descriptors) {
077        entries = new AppConfigurationEntry[descriptors.size()];
078        int i = 0;
079        for (LoginModuleDescriptor descriptor : descriptors) {
080            LoginModuleControlFlag flag = null;
081            if (descriptor.flag == null) {
082                flag = LoginModuleControlFlag.OPTIONAL;
083            } else if ("optional".equals(descriptor.flag)) {
084                flag = LoginModuleControlFlag.OPTIONAL;
085            } else if ("sufficient".equals(descriptor.flag)) {
086                flag = LoginModuleControlFlag.SUFFICIENT;
087            } else if ("required".equals(descriptor.flag)) {
088                flag = LoginModuleControlFlag.REQUIRED;
089            } else if ("requisite".equals(descriptor.flag)) {
090                flag = LoginModuleControlFlag.REQUISITE;
091            }
092            descriptor.options.put(LoginModuleWrapper.DELEGATE_CLASS_KEY, descriptor.code);
093            entries[i++] = new AppConfigurationEntry(LoginModuleWrapper.class.getName(), flag, descriptor.options);
094        }
095    }
096
097    public LoginContext login(Subject subject) throws LoginException {
098        LoginContext ctx = new LoginContext(name, subject);
099        ctx.login();
100        return ctx;
101    }
102
103    public LoginContext login(CallbackHandler handler) throws LoginException {
104        LoginContext ctx = new LoginContext(name, handler);
105        ctx.login();
106        return ctx;
107    }
108
109    public LoginContext login(Subject subject, CallbackHandler handler) throws LoginException {
110        LoginContext ctx = new LoginContext(name, subject, handler);
111        ctx.login();
112        return ctx;
113    }
114
115    public LoginContext login(String username, Object credentials) throws LoginException {
116        CredentialsCallbackHandler handler = new CredentialsCallbackHandler(username, credentials);
117        LoginContext ctx = new LoginContext(name, handler);
118        ctx.login();
119        return ctx;
120    }
121
122    public static String controlFlagToString(LoginModuleControlFlag flag) {
123        if (flag == LoginModuleControlFlag.OPTIONAL) {
124            return "optional";
125        } else if (flag == LoginModuleControlFlag.REQUIRED) {
126            return "required";
127        } else if (flag == LoginModuleControlFlag.REQUISITE) {
128            return "requisite";
129        } else if (flag == LoginModuleControlFlag.SUFFICIENT) {
130            return "sufficient";
131        }
132        throw new IllegalArgumentException("Not a supported LoginModuleControlFlag: " + flag);
133    }
134
135    public static LoginModuleControlFlag controlFlagFromString(String flag) {
136        if (flag == null) {
137            return LoginModuleControlFlag.OPTIONAL;
138        } else if ("optional".equals(flag)) {
139            return LoginModuleControlFlag.OPTIONAL;
140        } else if ("sufficient".equals(flag)) {
141            return LoginModuleControlFlag.SUFFICIENT;
142        } else if ("required".equals(flag)) {
143            return LoginModuleControlFlag.REQUIRED;
144        } else if ("requisite".equals(flag)) {
145            return LoginModuleControlFlag.REQUISITE;
146        }
147        throw new IllegalArgumentException("Not a supported LoginModuleControlFlag: " + flag);
148    }
149
150    @SuppressWarnings("unchecked")
151    private void readObject(ObjectInputStream in) throws ClassNotFoundException, IOException {
152        in.defaultReadObject();
153        // read app config entries
154        int size = in.readInt();
155        entries = new AppConfigurationEntry[size];
156        for (int i = 0; i < size; i++) {
157            String name = (String) in.readObject();
158            String ctrlFlag = (String) in.readObject();
159            LoginModuleControlFlag flag = controlFlagFromString(ctrlFlag);
160            Map<String, ?> opts = (Map<String, ?>) in.readObject();
161            entries[i] = new AppConfigurationEntry(name, flag, opts);
162        }
163    }
164
165    private void writeObject(ObjectOutputStream out) throws IOException {
166        out.defaultWriteObject();
167        // write app config entries
168        if (entries == null) {
169            out.writeInt(0);
170        } else {
171            out.writeInt(entries.length);
172            for (AppConfigurationEntry entry : entries) {
173                out.writeObject(entry.getLoginModuleName());
174                out.writeObject(controlFlagToString(entry.getControlFlag()));
175                Map<String, ?> opts = entry.getOptions();
176                if (!(opts instanceof Serializable)) {
177                    opts = new HashMap<String, Object>(opts);
178                }
179                out.writeObject(opts);
180            }
181        }
182    }
183
184}