package org.picketlink.idm.credential;
import org.picketlink.idm.IdentityManagementException;
import org.picketlink.idm.model.Account;
import org.picketlink.idm.model.IdentityType;
import org.picketlink.idm.model.annotation.StereotypeProperty;
import java.lang.reflect.Constructor;
import static org.picketlink.common.reflection.Reflections.classForName;
import static org.picketlink.common.reflection.Reflections.findDeclaredConstructor;
/**
* <p>Represents a token credential.</p>
*
* <p>Basically, a token is a self-contained repository for identities and claims for a particular subject.
*
* <p>Each token type has its own {@link org.picketlink.idm.credential.Token.Provider} and {@link org.picketlink.idm.credential.Token.Consumer}.
* The first is responsible for manage a specific token type (eg.: issue, renew, invalidate, etc). The latter is responsible for
* consume a specific token type, providing to clients all the necessary code to properly handle a specific token type.</p>
*
* @author Pedro Igor
*
* @see org.picketlink.idm.credential.Token.Provider
* @see org.picketlink.idm.credential.Token.Consumer
* @see org.picketlink.idm.credential.TokenCredential
* @see org.picketlink.idm.credential.handler.TokenCredentialHandler
*/
public interface Token {
/**
* <p>Returns the type of the token.</p>
*
* @return
*/
String getType();
/**
* <p>Returns the subject identifier. The identifier usually represents a unique and never reassigned identifier within the
* Issuer for the End-User. Which is intended to be consumed by the Client.</p>
*
* @return
*/
String getSubject();
/**
* <p>Returns the string representation of a token.</p>
*
* @return
*/
String getToken();
/**
* <p>
* Token providers are responsible to provide some importantant management operations for a specific {@link Token} type.
* </p>
*
* @author Pedor Igor
*/
public interface Provider<T extends Token> {
/**
* <p>Issues a new token for the given {@link org.picketlink.idm.model.Account}.</p>
*
* @param account
* @return
*/
T issue(Account account);
/**
* <p>
* Renew a token based on the current token in use.
* </p>
*
* @param renewToken
* @return
*/
T renew(Account account, T renewToken);
/**
* <p>Invalidates the current token for the given {@link org.picketlink.idm.model.Account}.</p>
*
* @param account
*/
void invalidate(Account account);
/**
* <p>Returns the {@link org.picketlink.idm.credential.Token} type supported by this provider.</p>
*
* @return
*/
Class<T> getTokenType();
}
/**
* <p>
* Token consumers are responsible to provide all the necessary support to consume information from a specific {@link org.picketlink.idm.credential.Token}.
* </p>
*
* @author Pedor Igor
*/
public interface Consumer<T extends Token> {
/**
* <p>Extracts a certain {@link org.picketlink.idm.model.IdentityType} considering the information from the given {@link Token}.</p>
*
* <p>Usually, a token contains a set of claims which can be mapped to the identity types supported by PicketLink {@link org.picketlink.idm.model.annotation.IdentityStereotype.Stereotype}.
* Each stereotype has a set of common properties that can be used to identify them. In this case, the {@link org.picketlink.idm.model.annotation.StereotypeProperty.Property} should be
* used to tell which property of the given identity type should be populated with the <code>identifier</code> value if there is any claim in the token representing it.</p>
*
* @param token The token.
* @param identityType The type of the identity type that should be created based on the claims of a token.
* @param stereotypeProperty The stereotype property used to identify and populate the identity type instance from the token claims.
* @param identifier The value of the identifier used to match the existence of a identity type based on the token claims set.
* @return An identity type instance of there is any claim from the token referencing it. Otherwise this method returns null.
*/
<I extends IdentityType> I extractIdentity(T token, Class<I> identityType, StereotypeProperty.Property stereotypeProperty, Object identifier);
/**
* <p>
* Validates a token.
* </p>
*
* @param token
* @return
*/
boolean validate(T token);
/**
* <p>Returns the {@link org.picketlink.idm.credential.Token} type supported by this consumer.</p>
*
* @return
*/
Class<T> getTokenType();
}
public static class Builder {
/**
* <p>Creates a {@link org.picketlink.idm.credential.Token} instance from the given {@link org.picketlink.idm.credential.storage.TokenCredentialStorage}.</p>
*
* @return
* @throws org.picketlink.idm.IdentityManagementException
*/
public static Token create(String tokenType, String tokenValue) throws IdentityManagementException {
try {
Class<Token> tokenClazz = classForName(tokenType);
Constructor<Token> expectedConstructor = (Constructor<Token>) findDeclaredConstructor(tokenClazz, String.class);
if (expectedConstructor == null) {
throw new IdentityManagementException("Token type [" + tokenClazz.getName() + "] must provide a constructor that accepts a String.");
}
return expectedConstructor.newInstance(tokenValue);
} catch (ClassCastException cce) {
throw new IdentityManagementException("Wrong Token type [" + tokenType + "]. It must be a subclass of [" + Token.class.getName() + "].", cce);
} catch (ClassNotFoundException cnfe) {
throw new IdentityManagementException("Token type not found [" + tokenType + "].", cnfe);
} catch (Exception e) {
throw new IdentityManagementException("Could not create Token type [" + tokenType + "].", e);
}
}
}
}