summaryrefslogtreecommitdiffstats
path: root/dozentenmodul/src/main/java/org/openslx/dozmod/authentication/ShibbolethEcp.java
blob: 1c6062b6305db0538c6bdc0172e859334beefa13 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
package org.openslx.dozmod.authentication;

import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.URL;

import org.apache.http.HttpResponse;
import org.apache.http.ParseException;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.util.EntityUtils;
import org.apache.log4j.Logger;
import org.openslx.bwlp.thrift.iface.AuthorizationError;
import org.openslx.bwlp.thrift.iface.TAuthorizationException;
import org.openslx.dozmod.Branding;
import org.openslx.dozmod.util.ProxyConfigurator;

import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.JsonSyntaxException;

import edu.kit.scc.dei.ecplean.ECPAuthenticationException;
import edu.kit.scc.dei.ecplean.ECPAuthenticator;

public class ShibbolethEcp {

	/**
	 * Logger instance for this class
	 */
	private final static Logger LOGGER = Logger.getLogger(ShibbolethEcp.class);

	/**
	 * Static gson object for (de)serialization
	 */
	private static final Gson GSON = new GsonBuilder().create();

	/**
	 * ServiceProviderResponse Object representing the last response we received
	 */
	private static ServiceProviderResponse lastResponse = null;
	/**
	 * URL for service registration
	 */
	private static URL registrationUrl = null;

	/**
	 * Return codes
	 */
	public static enum ReturnCode {
		// TODO rework this...
		NO_ERROR(0,
				"Authentication against the identity provider and request of the service provider resource worked."),
		IDENTITY_PROVIDER_ERROR(1, "Authentication against the identity provider failed."),
		UNREGISTERED_ERROR(2, "User not registered to use " + Branding.getServiceName() + "."),
		SERVICE_PROVIDER_ERROR(3, "Invalid resource of the service provider."),
		INVALID_URL_ERROR(4, "Invalid URL received from master server."),
		GENERIC_ERROR(5, "Internal error.");

		private final int id;
		private final String msg;

		ReturnCode(int id, String msg) {
			this.id = id;
			this.msg = msg;
		}

		public int getId() {
			return this.id;
		}

		public String getMsg() {
			return this.msg;
		}
	}

	/**
	 * Static URI to the SP.
	 */
	public final static URI BWLP_SP;
	static {
		URI tmp;
		try {
			tmp = new URI("https://" + Branding.getMasterServerAddress() + "/webif/shib/api.php");
		} catch (URISyntaxException e) {
			// should never happen!
			LOGGER.error("Bad URI syntax of the service provider, see trace: ", e);
			tmp = null;
		}
		BWLP_SP = tmp;
	}

	public static ServiceProviderResponse getResponse() {
		return lastResponse;
	}

	/**
	 * Fetches the resource
	 * 
	 * @param idpUrl
	 *            URL of the identity provider to authenticate against, as
	 *            String.
	 * @param user
	 *            Username as String.
	 * @param pass
	 *            Password as String.
	 * @return
	 *         true if login worked, false otherwise.
	 * @throws TAuthorizationException
	 */
	public static ReturnCode doLogin(final String idpUrl, final String user, final String pass)
			throws TAuthorizationException, URISyntaxException, ClientProtocolException, IOException,
			ParseException, JsonSyntaxException, MalformedURLException {

		// first lets do some sanity checks
		if (BWLP_SP == null) {
			LOGGER.error("URI to service provider is not set. Check the initialization of 'BWLP_SP'.");
			return ReturnCode.GENERIC_ERROR;
		}
		if (idpUrl == null) {
			LOGGER.error("Identity provider is not set, did you initialize this class correctly?");
			return ReturnCode.GENERIC_ERROR;
		}
		if (user == null) {
			LOGGER.error("No username given, aborting...");
			return ReturnCode.GENERIC_ERROR;
		}
		if (pass == null) {
			LOGGER.error("No password given, aborting...");
			return ReturnCode.GENERIC_ERROR;
		}

		// now init the authenticator for that idp and our static sp
		final ECPAuthenticator auth = new ECPAuthenticator(ProxyConfigurator.getClient(), user, pass, new URI(idpUrl), BWLP_SP);
		auth.setRetryWithoutAt(true);

		HttpResponse spResponse;
		try {
			spResponse = auth.authenticate();
		} catch (ECPAuthenticationException e) {
			LOGGER.error("ECP Authentication Exception, see trace: ", e);
			throw new TAuthorizationException(AuthorizationError.GENERIC_ERROR, e.getMessage());
		}

		if (spResponse.getStatusLine().getStatusCode() != 200) {
			LOGGER.error("SP does not return HTTP status code 200");
			throw new TAuthorizationException(AuthorizationError.GENERIC_ERROR, "SP says: "
					+ spResponse.getStatusLine().toString());
		}
		
		LOGGER.debug("Login complete, getting body");

		final String responseBody = EntityUtils.toString(spResponse.getEntity());
		
		try {
			lastResponse = GSON.fromJson(responseBody, ServiceProviderResponse.class);
		} catch (JsonSyntaxException e) {
			LOGGER.warn("Json data from Service Provider malformed", e);
			LOGGER.warn("Response was:\n" + responseBody);
			throw e;
		}
		
		// TODO: here we will need to parse the answer accordingly.
		// no errors, meaning everything worked fine.
		if (lastResponse.status.equals("unregistered")) {
			registrationUrl = new URL(lastResponse.url);
			return ReturnCode.UNREGISTERED_ERROR;
		}
		// TODO the rest of the cases...
		if (lastResponse.status.equals("error")) {
			LOGGER.error("Server side error: " + lastResponse.error);
			return ReturnCode.GENERIC_ERROR;
		}
		if (lastResponse.status.equals("anonymous")) {
			LOGGER.error("IdP did not forward user account information to SP. Contact developer.");
			lastResponse.error = "Ihr Identity-Provider hat dem " + Branding.getServiceName() + "-System Ihre E-Mail oder Ihren Namen nicht mitgeteilt";
			return ReturnCode.GENERIC_ERROR;
		}
		if (lastResponse.status.equals("ok")) {
			return ReturnCode.NO_ERROR;
		}
		// still here? then something else went wrong
		return ReturnCode.GENERIC_ERROR;
	}

	/**
	 * @return Registration URL given by the SP.
	 */
	public static URL getRegistrationUrl() {
		return registrationUrl;
	}
}