View Javadoc
1   package org.argeo.cms.internal.http.client;
2   
3   import java.net.URL;
4   import java.security.PrivilegedExceptionAction;
5   import java.util.ArrayList;
6   import java.util.Base64;
7   
8   import javax.security.auth.Subject;
9   import javax.security.auth.login.LoginContext;
10  
11  import org.apache.commons.httpclient.Credentials;
12  import org.apache.commons.httpclient.HttpClient;
13  import org.apache.commons.httpclient.HttpMethod;
14  import org.apache.commons.httpclient.URIException;
15  import org.apache.commons.httpclient.auth.AuthPolicy;
16  import org.apache.commons.httpclient.auth.AuthScheme;
17  import org.apache.commons.httpclient.auth.AuthenticationException;
18  import org.apache.commons.httpclient.auth.CredentialsProvider;
19  import org.apache.commons.httpclient.auth.MalformedChallengeException;
20  import org.apache.commons.httpclient.methods.GetMethod;
21  import org.apache.commons.httpclient.params.DefaultHttpParams;
22  import org.apache.commons.httpclient.params.HttpParams;
23  import org.argeo.cms.internal.kernel.KernelConstants;
24  import org.ietf.jgss.GSSContext;
25  import org.ietf.jgss.GSSException;
26  import org.ietf.jgss.GSSManager;
27  import org.ietf.jgss.GSSName;
28  import org.ietf.jgss.Oid;
29  
30  /** Implementation of the SPNEGO auth scheme. */
31  public class SpnegoAuthScheme implements AuthScheme {
32  //	private final static Log log = LogFactory.getLog(SpnegoAuthScheme.class);
33  
34  	public static final String NAME = "Negotiate";
35  	private final static Oid KERBEROS_OID;
36  	static {
37  		try {
38  			KERBEROS_OID = new Oid("1.3.6.1.5.5.2");
39  		} catch (GSSException e) {
40  			throw new IllegalStateException("Cannot create Kerberos OID", e);
41  		}
42  	}
43  
44  	private boolean complete = false;
45  	private String realm;
46  
47  	@Override
48  	public void processChallenge(String challenge) throws MalformedChallengeException {
49  		// if(tokenStr!=null){
50  		// log.error("Received challenge while there is a token. Failing.");
51  		// complete = false;
52  		// }
53  
54  	}
55  
56  	@Override
57  	public String getSchemeName() {
58  		return NAME;
59  	}
60  
61  	@Override
62  	public String getParameter(String name) {
63  		return null;
64  	}
65  
66  	@Override
67  	public String getRealm() {
68  		return realm;
69  	}
70  
71  	@Override
72  	public String getID() {
73  		return NAME;
74  	}
75  
76  	@Override
77  	public boolean isConnectionBased() {
78  		return true;
79  	}
80  
81  	@Override
82  	public boolean isComplete() {
83  		return complete;
84  	}
85  
86  	@Override
87  	public String authenticate(Credentials credentials, String method, String uri) throws AuthenticationException {
88  		// log.debug("authenticate " + method + " " + uri);
89  		// return null;
90  		throw new UnsupportedOperationException();
91  	}
92  
93  	@Override
94  	public String authenticate(Credentials credentials, HttpMethod method) throws AuthenticationException {
95  		GSSContext context = null;
96  		String tokenStr = null;
97  		String hostname;
98  		try {
99  			hostname = method.getURI().getHost();
100 		} catch (URIException e1) {
101 			throw new IllegalStateException("Cannot authenticate", e1);
102 		}
103 		String serverPrinc = KernelConstants.DEFAULT_KERBEROS_SERVICE + "@" + hostname;
104 
105 		try {
106 			// Get service's principal name
107 			GSSManager manager = GSSManager.getInstance();
108 			GSSName serverName = manager.createName(serverPrinc, GSSName.NT_HOSTBASED_SERVICE, KERBEROS_OID);
109 
110 			// Get the context for authentication
111 			context = manager.createContext(serverName, KERBEROS_OID, null, GSSContext.DEFAULT_LIFETIME);
112 			// context.requestMutualAuth(true); // Request mutual authentication
113 			// context.requestConf(true); // Request confidentiality
114 			context.requestCredDeleg(true);
115 
116 			byte[] token = new byte[0];
117 
118 			// token is ignored on the first call
119 			token = context.initSecContext(token, 0, token.length);
120 
121 			// Send a token to the server if one was generated by
122 			// initSecContext
123 			if (token != null) {
124 				tokenStr = Base64.getEncoder().encodeToString(token);
125 				// complete=true;
126 			}
127 			return "Negotiate " + tokenStr;
128 		} catch (GSSException e) {
129 			complete = true;
130 			throw new AuthenticationException("Cannot authenticate to " + serverPrinc, e);
131 		}
132 	}
133 
134 	public static void main(String[] args) {
135 		if (args.length == 0) {
136 			System.err.println("usage: java " + SpnegoAuthScheme.class.getName() + " <url>");
137 			System.exit(1);
138 			return;
139 		}
140 		String url = args[0];
141 
142 		URL jaasUrl = SpnegoAuthScheme.class.getResource("jaas.cfg");
143 		System.setProperty("java.security.auth.login.config", jaasUrl.toExternalForm());
144 		try {
145 			LoginContext lc = new LoginContext("SINGLE_USER");
146 			lc.login();
147 
148 			AuthPolicy.registerAuthScheme(SpnegoAuthScheme.NAME, SpnegoAuthScheme.class);
149 			HttpParams params = DefaultHttpParams.getDefaultParams();
150 			ArrayList<String> schemes = new ArrayList<>();
151 			schemes.add(SpnegoAuthScheme.NAME);
152 			params.setParameter(AuthPolicy.AUTH_SCHEME_PRIORITY, schemes);
153 			params.setParameter(CredentialsProvider.PROVIDER, new HttpCredentialProvider());
154 
155 			int responseCode = Subject.doAs(lc.getSubject(), new PrivilegedExceptionAction<Integer>() {
156 				public Integer run() throws Exception {
157 					HttpClient httpClient = new HttpClient();
158 					return httpClient.executeMethod(new GetMethod(url));
159 				}
160 			});
161 			System.out.println("Reponse code: " + responseCode);
162 		} catch (Exception e) {
163 			e.printStackTrace();
164 		}
165 	}
166 
167 }