1//
2//  ========================================================================
3//  Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd.
4//  ------------------------------------------------------------------------
5//  All rights reserved. This program and the accompanying materials
6//  are made available under the terms of the Eclipse Public License v1.0
7//  and Apache License v2.0 which accompanies this distribution.
8//
9//      The Eclipse Public License is available at
10//      http://www.eclipse.org/legal/epl-v10.html
11//
12//      The Apache License v2.0 is available at
13//      http://www.opensource.org/licenses/apache2.0.php
14//
15//  You may elect to redistribute this code under either of these licenses.
16//  ========================================================================
17//
18
19package org.eclipse.jetty.security;
20
21import java.util.Properties;
22
23import javax.security.auth.Subject;
24
25import org.eclipse.jetty.server.UserIdentity;
26import org.eclipse.jetty.util.component.AbstractLifeCycle;
27import org.eclipse.jetty.util.log.Log;
28import org.eclipse.jetty.util.log.Logger;
29import org.eclipse.jetty.util.resource.Resource;
30import org.eclipse.jetty.util.security.B64Code;
31import org.ietf.jgss.GSSContext;
32import org.ietf.jgss.GSSCredential;
33import org.ietf.jgss.GSSException;
34import org.ietf.jgss.GSSManager;
35import org.ietf.jgss.GSSName;
36import org.ietf.jgss.Oid;
37
38public class SpnegoLoginService extends AbstractLifeCycle implements LoginService
39{
40    private static final Logger LOG = Log.getLogger(SpnegoLoginService.class);
41
42    protected IdentityService _identityService;// = new LdapIdentityService();
43    protected String _name;
44    private String _config;
45
46    private String _targetName;
47
48    public SpnegoLoginService()
49    {
50
51    }
52
53    public SpnegoLoginService( String name )
54    {
55        setName(name);
56    }
57
58    public SpnegoLoginService( String name, String config )
59    {
60        setName(name);
61        setConfig(config);
62    }
63
64    public String getName()
65    {
66        return _name;
67    }
68
69    public void setName(String name)
70    {
71        if (isRunning())
72        {
73            throw new IllegalStateException("Running");
74        }
75
76        _name = name;
77    }
78
79    public String getConfig()
80    {
81        return _config;
82    }
83
84    public void setConfig( String config )
85    {
86        if (isRunning())
87        {
88            throw new IllegalStateException("Running");
89        }
90
91        _config = config;
92    }
93
94
95
96    @Override
97    protected void doStart() throws Exception
98    {
99        Properties properties = new Properties();
100        Resource resource = Resource.newResource(_config);
101        properties.load(resource.getInputStream());
102
103        _targetName = properties.getProperty("targetName");
104
105        LOG.debug("Target Name {}", _targetName);
106
107        super.doStart();
108    }
109
110    /**
111     * username will be null since the credentials will contain all the relevant info
112     */
113    public UserIdentity login(String username, Object credentials)
114    {
115        String encodedAuthToken = (String)credentials;
116
117        byte[] authToken = B64Code.decode(encodedAuthToken);
118
119        GSSManager manager = GSSManager.getInstance();
120        try
121        {
122            Oid krb5Oid = new Oid("1.3.6.1.5.5.2"); // http://java.sun.com/javase/6/docs/technotes/guides/security/jgss/jgss-features.html
123            GSSName gssName = manager.createName(_targetName,null);
124            GSSCredential serverCreds = manager.createCredential(gssName,GSSCredential.INDEFINITE_LIFETIME,krb5Oid,GSSCredential.ACCEPT_ONLY);
125            GSSContext gContext = manager.createContext(serverCreds);
126
127            if (gContext == null)
128            {
129                LOG.debug("SpnegoUserRealm: failed to establish GSSContext");
130            }
131            else
132            {
133                while (!gContext.isEstablished())
134                {
135                    authToken = gContext.acceptSecContext(authToken,0,authToken.length);
136                }
137                if (gContext.isEstablished())
138                {
139                    String clientName = gContext.getSrcName().toString();
140                    String role = clientName.substring(clientName.indexOf('@') + 1);
141
142                    LOG.debug("SpnegoUserRealm: established a security context");
143                    LOG.debug("Client Principal is: " + gContext.getSrcName());
144                    LOG.debug("Server Principal is: " + gContext.getTargName());
145                    LOG.debug("Client Default Role: " + role);
146
147                    SpnegoUserPrincipal user = new SpnegoUserPrincipal(clientName,authToken);
148
149                    Subject subject = new Subject();
150                    subject.getPrincipals().add(user);
151
152                    return _identityService.newUserIdentity(subject,user, new String[]{role});
153                }
154            }
155
156        }
157        catch (GSSException gsse)
158        {
159            LOG.warn(gsse);
160        }
161
162        return null;
163    }
164
165    public boolean validate(UserIdentity user)
166    {
167        return false;
168    }
169
170    public IdentityService getIdentityService()
171    {
172        return _identityService;
173    }
174
175    public void setIdentityService(IdentityService service)
176    {
177        _identityService = service;
178    }
179
180	public void logout(UserIdentity user) {
181		// TODO Auto-generated method stub
182
183	}
184
185}
186