]> git.argeo.org Git - lgpl/argeo-commons.git/blob - org.argeo.cms/src/org/argeo/cms/auth/RemoteAuthUtils.java
Fix E4 devops
[lgpl/argeo-commons.git] / org.argeo.cms / src / org / argeo / cms / auth / RemoteAuthUtils.java
1 package org.argeo.cms.auth;
2
3 import java.security.AccessControlContext;
4 import java.security.AccessController;
5 import java.security.PrivilegedAction;
6 import java.util.Base64;
7 import java.util.function.Supplier;
8
9 import javax.security.auth.Subject;
10 import javax.security.auth.kerberos.KerberosTicket;
11 import javax.security.auth.login.LoginContext;
12 import javax.security.auth.login.LoginException;
13
14 import org.argeo.api.cms.CmsAuth;
15 import org.argeo.api.cms.CmsLog;
16 import org.argeo.api.cms.CmsSession;
17 import org.argeo.cms.internal.runtime.CmsContextImpl;
18 import org.argeo.util.http.HttpHeader;
19 import org.ietf.jgss.GSSContext;
20 import org.ietf.jgss.GSSException;
21 import org.ietf.jgss.GSSManager;
22 import org.ietf.jgss.GSSName;
23 import org.ietf.jgss.Oid;
24
25 /** Remote authentication utilities. */
26 public class RemoteAuthUtils {
27 private final static CmsLog log = CmsLog.getLog(RemoteAuthUtils.class);
28
29 static final String REMOTE_USER = "org.osgi.service.http.authentication.remote.user";
30 private final static Oid KERBEROS_OID;
31 // private final static Oid KERB_V5_OID, KRB5_PRINCIPAL_NAME_OID;
32 static {
33 try {
34 KERBEROS_OID = new Oid("1.3.6.1.5.5.2");
35 // KERB_V5_OID = new Oid("1.2.840.113554.1.2.2");
36 // KRB5_PRINCIPAL_NAME_OID = new Oid("1.2.840.113554.1.2.2.1");
37 } catch (GSSException e) {
38 throw new IllegalStateException("Cannot create Kerberos OID", e);
39 }
40 }
41
42 /**
43 * Execute this supplier, using the CMS class loader as context classloader.
44 * Useful to log in to JCR.
45 */
46 public final static <T> T doAs(Supplier<T> supplier, RemoteAuthRequest req) {
47 ClassLoader currentContextCl = Thread.currentThread().getContextClassLoader();
48 Thread.currentThread().setContextClassLoader(RemoteAuthUtils.class.getClassLoader());
49 try {
50 return Subject.doAs(
51 Subject.getSubject((AccessControlContext) req.getAttribute(AccessControlContext.class.getName())),
52 new PrivilegedAction<T>() {
53
54 @Override
55 public T run() {
56 return supplier.get();
57 }
58
59 });
60 } finally {
61 Thread.currentThread().setContextClassLoader(currentContextCl);
62 }
63 }
64
65 public final static void configureRequestSecurity(RemoteAuthRequest req) {
66 if (req.getAttribute(AccessControlContext.class.getName()) != null)
67 throw new IllegalStateException("Request already authenticated.");
68 AccessControlContext acc = AccessController.getContext();
69 req.setAttribute(REMOTE_USER, CurrentUser.getUsername());
70 req.setAttribute(AccessControlContext.class.getName(), acc);
71 }
72
73 public final static void clearRequestSecurity(RemoteAuthRequest req) {
74 if (req.getAttribute(AccessControlContext.class.getName()) == null)
75 throw new IllegalStateException("Cannot clear non-authenticated request.");
76 req.setAttribute(REMOTE_USER, null);
77 req.setAttribute(AccessControlContext.class.getName(), null);
78 }
79
80 public static CmsSession getCmsSession(RemoteAuthRequest req) {
81 Subject subject = Subject
82 .getSubject((AccessControlContext) req.getAttribute(AccessControlContext.class.getName()));
83 CmsSession cmsSession = CmsContextImpl.getCmsContext().getCmsSession(subject);
84 return cmsSession;
85 }
86
87 public static String getGssToken(Subject subject, String service, String server) {
88 if (subject.getPrivateCredentials(KerberosTicket.class).isEmpty())
89 throw new IllegalArgumentException("Subject " + subject + " is not GSS authenticated.");
90 return Subject.doAs(subject, (PrivilegedAction<String>) () -> {
91 // !! different format than Kerberos
92 String serverPrinc = service + "@" + server;
93 GSSContext context = null;
94 String tokenStr = null;
95
96 try {
97 // Get service's principal name
98 GSSManager manager = GSSManager.getInstance();
99 // GSSName serverName = manager.createName(serverPrinc,
100 // GSSName.NT_HOSTBASED_SERVICE, KERBEROS_OID);
101 GSSName serverName = manager.createName(serverPrinc, GSSName.NT_HOSTBASED_SERVICE);
102
103 // Get the context for authentication
104 context = manager.createContext(serverName, KERBEROS_OID, null, GSSContext.DEFAULT_LIFETIME);
105 // context.requestMutualAuth(true); // Request mutual authentication
106 // context.requestConf(true); // Request confidentiality
107 context.requestCredDeleg(true);
108
109 byte[] token = new byte[0];
110
111 // token is ignored on the first call
112 token = context.initSecContext(token, 0, token.length);
113
114 // Send a token to the server if one was generated by
115 // initSecContext
116 if (token != null) {
117 tokenStr = Base64.getEncoder().encodeToString(token);
118 // complete=true;
119 }
120 return tokenStr;
121
122 } catch (GSSException e) {
123 throw new IllegalStateException("Cannot authenticate to " + serverPrinc, e);
124 }
125 });
126 }
127
128 public static LoginContext anonymousLogin(RemoteAuthRequest remoteAuthRequest,
129 RemoteAuthResponse remoteAuthResponse) {
130 // anonymous
131 ClassLoader currentContextClassLoader = Thread.currentThread().getContextClassLoader();
132 try {
133 Thread.currentThread().setContextClassLoader(RemoteAuthUtils.class.getClassLoader());
134 LoginContext lc = CmsAuth.ANONYMOUS
135 .newLoginContext(new RemoteAuthCallbackHandler(remoteAuthRequest, remoteAuthResponse));
136 lc.login();
137 return lc;
138 } catch (LoginException e1) {
139 if (log.isDebugEnabled())
140 log.error("Cannot log in as anonymous", e1);
141 return null;
142 } finally {
143 Thread.currentThread().setContextClassLoader(currentContextClassLoader);
144 }
145 }
146
147 public static int askForWwwAuth(RemoteAuthResponse remoteAuthResponse, String realm, boolean forceBasic) {
148 // response.setHeader(HttpUtils.HEADER_WWW_AUTHENTICATE, "basic
149 // realm=\"" + httpAuthRealm + "\"");
150 if (hasAcceptorCredentials() && !forceBasic)// SPNEGO
151 remoteAuthResponse.setHeader(HttpHeader.WWW_AUTHENTICATE.getName(), HttpHeader.NEGOTIATE);
152 else
153 remoteAuthResponse.setHeader(HttpHeader.WWW_AUTHENTICATE.getName(),
154 HttpHeader.BASIC + " " + HttpHeader.REALM + "=\"" + realm + "\"");
155
156 // response.setDateHeader("Date", System.currentTimeMillis());
157 // response.setDateHeader("Expires", System.currentTimeMillis() + (24 *
158 // 60 * 60 * 1000));
159 // response.setHeader("Accept-Ranges", "bytes");
160 // response.setHeader("Connection", "Keep-Alive");
161 // response.setHeader("Keep-Alive", "timeout=5, max=97");
162 // response.setContentType("text/html; charset=UTF-8");
163
164 return 401;
165 }
166
167 private static boolean hasAcceptorCredentials() {
168 return CmsContextImpl.getCmsContext().getAcceptorCredentials() != null;
169 }
170
171 }