act.ws.SecureTicketCodec Maven / Gradle / Ivy
package act.ws;
/*-
* #%L
* ACT Framework
* %%
* Copyright (C) 2014 - 2017 ActFramework
* %%
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* #L%
*/
import org.osgl.$;
import org.osgl.http.H;
import org.osgl.util.C;
import org.osgl.util.S;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
/**
* Encode/decode a secure ticket from/to {@link H.Session}, or part of the session info
* @param the encoded type
*/
public interface SecureTicketCodec {
/**
* Generate a secure ticket from a session data
* @param session the session data
* @return a secure ticket
*/
T createTicket(H.Session session);
/**
* Parse a secure ticket and construct a session data. Note
* if the `ticket` specified is invalid then it shall return
* a `null` session
*
* @param ticket the secure ticket
* @return a session data from the ticket or `null` if the ticket is invalid to this codec
*/
H.Session parseTicket(T ticket);
/**
* Do sanity check on an object to quickly probe if it is a
* ticket that can be processed by this codec
*
* @param ticket the object to be tested
* @return `true` if the codec believe it can process the ticket or `false` if not sure
*/
boolean probeTicket(Object ticket);
abstract class Base implements SecureTicketCodec {
/**
* Encode the session id and payload data into the ticket with type ``
* @param id the session id
* @param payload the payload data
* @return the ticket
*/
protected abstract T serialize(String id, Map payload);
/**
* Decode the ticket and return the session ID and fill the payload map
*
* Note if the ticket is invalid, the implementation shall return a `null`
* `id` and leave the `payload` map untouched
*
* @param ticket the ticket to be decoded
* @param payload a Map passed in to be filled with decoded payload
* @return the session ID decoded from the ticket specified
*/
protected abstract String deserialize(T ticket, Map payload);
private Set keys;
public Base() {this(C.set());}
public Base(Collection keys) {
this.keys = C.set($.requireNotNull(keys));
}
public Base(String ... keys) {
this(C.listOf(keys));
}
public Base(String keys) {
this(C.listOf(keys.split(S.COMMON_SEP)));
}
@Override
public final T createTicket(H.Session session) {
String id = session.id();
Map map = new HashMap<>();
Set keys = this.keys;
if (keys.isEmpty()) {
keys = C.newSet(session.keySet());
keys.remove(H.Session.KEY_EXPIRATION);
keys.remove(H.Session.KEY_ID);
}
for (String key : keys) {
String val = session.get(key);
if (null != val) {
map.put(key, val);
}
}
return serialize(id, map);
}
@Override
public final H.Session parseTicket(T ticket) {
Map payload = new HashMap<>();
String id = deserialize(ticket, payload);
if (null == payload) {
return null;
}
H.Session session = new H.Session();
$.setField("id", session, id);
if (payload.isEmpty()) {
return session;
}
for (Map.Entry entry : payload.entrySet()) {
session.put(entry.getKey(), entry.getValue());
}
return session;
}
}
}