Search in sources :

Example 1 with StateAttribute

use of org.forgerock.openam.radius.common.StateAttribute in project OpenAM by OpenRock.

the class OpenAMAuthHandler method handle.

/**
     * Handles the request in potentially two distinct ways depending on whether a state attribute is found in the
     * request or not. When no state field is found this is an initial request starting the authentication process and
     * the request will have username and password embedded and ready for consumption by the first module in the chain.
     * Any request with a state attribute is a user response to a previous challenge response that we sent back to them
     * in a previously started authentication process. The number of challenge responses that are sent and their
     * corresponding replies is dependent upon the number of modules in the chain and the number of callback fields in
     * each set of callbacks. A set of callbacks represents one grouping of data needed by a module to complete its next
     * step in the authentication process that it implements. This grouping in a web environment constitutes a single
     * page into which a number of fields can receive data. However, to gather additional feedback from a user the
     * radius protocol only supports a challenge response with a text message and state and radius clients typically
     * present that message and a single text input field with a label like, "Answer", and submit and cancel buttons.
     * This means that we only get a single answer per radius challenge response. Therefore, for some callback groupings
     * we will need to return multiple challenge responses before we can submit the callback set's user response values
     * back to the module to take the next step in authentication.
     *
     * @param request
     *            the access request
     * @param response
     *            - the response to be sent to the client.
     * @param context
     *            - provides methods that the handler can use to obtain information about the context in which the
     *            request was made, for example the name and IP address of the client from which the request was
     *            received.
     * @return
     * @throws RadiusProcessingException
     *             - when the response can not be sent.
     */
@Override
public void handle(RadiusRequest request, RadiusResponse response, RadiusRequestContext context) throws RadiusProcessingException {
    LOG.message("Entering OpenAMAuthHandler.handle");
    response.setRealm(realm);
    final StateAttribute state = (StateAttribute) request.getAttribute(StateAttribute.class);
    ContextHolder holder = null;
    if (state != null) {
        final String cacheKey = state.getState();
        holder = contextCache.get(cacheKey);
    }
    // always get password attribute regardless of whether starting or returning more input since user input is
    // always sent via the password field.
    final UserPasswordAttribute credAtt = (UserPasswordAttribute) request.getAttribute(UserPasswordAttribute.class);
    String credential = null;
    try {
        credential = credAtt.extractPassword(context.getRequestAuthenticator(), context.getClientSecret());
    } catch (final IOException e) {
        LOG.error("Unable to extract credential field from RADIUS request. Denying Access.", e);
        rejectAccessAndTerminateProcess(response, holder);
        LOG.message("Leaving OpenAMAuthHandler.handle();");
        return;
    }
    if (holder == null) {
        holder = this.contextCache.createCachedContextHolder();
        request.setContextHolderKey(holder.getCacheKey());
        eventBus.post(new AuthRequestReceivedEvent(request, response, context));
        final UserNameAttribute usrAtt = (UserNameAttribute) request.getAttribute(UserNameAttribute.class);
        holder = startAuthProcess(holder, response, usrAtt, credential);
        if (holder == null || holder.getAuthPhase() == ContextHolder.AuthPhase.TERMINATED) {
            // oops. something happened and reject message was already sent. so drop out here.
            LOG.message("Leaving OpenAMAuthHandler.handle(); Auth phase is TERMINATED.");
            return;
        }
    } else {
        request.setContextHolderKey(holder.getCacheKey());
        eventBus.post(new AuthRequestReceivedEvent(request, response, context));
    }
    gatherUserInput(response, holder, credential, state);
    if (holder.getAuthPhase() == ContextHolder.AuthPhase.FINALIZING) {
        finalizeAuthProcess(response, holder);
    }
    LOG.message("Leaving OpenAMAuthHandler.handle();");
    return;
}
Also used : StateAttribute(org.forgerock.openam.radius.common.StateAttribute) AuthRequestReceivedEvent(org.forgerock.openam.radius.server.events.AuthRequestReceivedEvent) ContextHolder(org.forgerock.openam.radius.server.spi.handlers.amhandler.ContextHolder) UserNameAttribute(org.forgerock.openam.radius.common.UserNameAttribute) IOException(java.io.IOException) UserPasswordAttribute(org.forgerock.openam.radius.common.UserPasswordAttribute)

Example 2 with StateAttribute

use of org.forgerock.openam.radius.common.StateAttribute in project OpenAM by OpenRock.

the class ConsoleClient method run.

/**
     * Calls the server in a thread.
     */
@Override
public void run() {
    try {
        final DatagramChannel chan = DatagramChannel.open();
        // request id
        short reqId = 1;
        final SecureRandom random = new SecureRandom();
        final InetSocketAddress serverAddr = new InetSocketAddress(this.host, this.port);
        final NASIPAddressAttribute nasAddr = new NASIPAddressAttribute(InetAddress.getLocalHost());
        final NASPortAttribute nasPort = new NASPortAttribute(chan.socket().getLocalPort());
        StateAttribute state = null;
        // String username = "boydmr"; // TODO: restore
        final String username = getUserInputFor("Username", null);
        // String passwordOrAnswer = "password"; // TODO: restore
        String passwordOrAnswer = getUserInputFor("Password", null);
        System.out.println();
        boolean finished = false;
        // ready for writing
        final ByteBuffer bufIn = ByteBuffer.allocate(4096);
        while (!finished) {
            final RequestAuthenticator reqAuthR = new RequestAuthenticator(random, this.secret);
            final AccessRequest req = new AccessRequest(reqId++, reqAuthR);
            req.addAttribute(new UserNameAttribute(username));
            req.addAttribute(new UserPasswordAttribute(req.getAuthenticator(), this.secret, passwordOrAnswer));
            req.addAttribute(nasAddr);
            req.addAttribute(nasPort);
            if (state != null) {
                req.addAttribute(state);
            }
            final ByteBuffer reqBuf = ByteBuffer.wrap(req.getOctets());
            if (logTraffic) {
                System.out.println("Packet To " + host + ":" + port);
                System.out.println(RadiusRequestContext.getPacketRepresentation(req));
            }
            chan.send(reqBuf, serverAddr);
            // now handle responses possibly sending additional requests
            chan.receive(bufIn);
            // prepare buffer for reading out
            bufIn.flip();
            final Packet res = PacketFactory.toPacket(bufIn);
            // prepare buffer for next response
            bufIn.clear();
            if (logTraffic) {
                System.out.println("Packet From " + host + ":" + port);
                System.out.println(RadiusRequestContext.getPacketRepresentation(res));
            }
            if (res instanceof AccessReject) {
                System.out.println("---> Sorry. Not Authenticated.");
                System.out.println();
                finished = true;
            } else if (res instanceof AccessAccept) {
                System.out.println("---> SUCCESS! You've Authenticated!");
                System.out.println();
                finished = true;
            } else if (res instanceof AccessChallenge) {
                final AccessChallenge chng = (AccessChallenge) res;
                state = (StateAttribute) getAttribute(StateAttribute.class, res);
                final ReplyMessageAttribute msg = (ReplyMessageAttribute) getAttribute(ReplyMessageAttribute.class, res);
                String message = null;
                if (msg != null) {
                    message = msg.getMessage();
                }
                passwordOrAnswer = getUserInputFor("Answer", message);
                System.out.println();
            }
        }
    } catch (final Exception e) {
        e.printStackTrace();
    }
}
Also used : StateAttribute(org.forgerock.openam.radius.common.StateAttribute) Packet(org.forgerock.openam.radius.common.Packet) RequestAuthenticator(org.forgerock.openam.radius.common.RequestAuthenticator) AccessRequest(org.forgerock.openam.radius.common.AccessRequest) InetSocketAddress(java.net.InetSocketAddress) DatagramChannel(java.nio.channels.DatagramChannel) SecureRandom(java.security.SecureRandom) NASIPAddressAttribute(org.forgerock.openam.radius.common.packet.NASIPAddressAttribute) ByteBuffer(java.nio.ByteBuffer) IOException(java.io.IOException) ReplyMessageAttribute(org.forgerock.openam.radius.common.ReplyMessageAttribute) UserNameAttribute(org.forgerock.openam.radius.common.UserNameAttribute) AccessReject(org.forgerock.openam.radius.common.AccessReject) NASPortAttribute(org.forgerock.openam.radius.common.packet.NASPortAttribute) AccessChallenge(org.forgerock.openam.radius.common.AccessChallenge) UserPasswordAttribute(org.forgerock.openam.radius.common.UserPasswordAttribute) AccessAccept(org.forgerock.openam.radius.common.AccessAccept)

Example 3 with StateAttribute

use of org.forgerock.openam.radius.common.StateAttribute in project OpenAM by OpenRock.

the class OpenAMAuthHandler method gatherUserInput.

private void gatherUserInput(RadiusResponse response, ContextHolder holder, String answer, StateAttribute state) {
    LOG.message("Entering gatherUserInput();");
    // a challenge response, get the next set loaded, and then start sending a challenges for that set.
    while (holder.getAuthPhase() == ContextHolder.AuthPhase.GATHERING_INPUT) {
        if (holder.getCallbacks() == null) {
            LOG.message("--- callbacks == null in gatherUserInput");
            // either just starting process or just finished submitting a set of callback input values
            if (!isNextCallbackSetAvailable(response, holder)) {
                // no further input from user needed or error occurred
                if (holder.getAuthPhase() == ContextHolder.AuthPhase.TERMINATED) {
                    return;
                }
                LOG.message("--- NextCallbackSet not-available in gatherUserInput - move to finalization");
                holder.setAuthPhase(ContextHolder.AuthPhase.FINALIZING);
                return;
            }
        } else {
            LOG.warning("--- callbacks[" + holder.getCallbacks().length + "] in gatherUserInput - ");
            // we are gathering for current set.
            // answers
            final boolean injected = injectAnswerForCallback(response, holder, answer);
            if (!injected) {
                // couldn't inject and already sent reject response so exit out
                return;
            }
        }
        // new callbacks available or still gathering input for the current set. if all callbacks have values
        // then submit and loop around again to get next set else send challenge response to gather input for the
        // next callback
        final Callback[] callbacks = holder.getCallbacks();
        if (holder.getIdxOfCurrentCallback() > callbacks.length - 1) {
            LOG.warning("--- holder.idxOfCurrentCallback " + holder.getIdxOfCurrentCallback() + " > holder.callbacks.length-1 " + (holder.getCallbacks().length - 1) + " in gatherUserInput - submitting/set callbacks=null");
            try {
                holder.getAuthContext().submitRequirements(callbacks);
            } catch (final Throwable t) {
                LOG.error("Exception thrown while submitting callbacks. Rejecting access.", t);
                rejectAccessAndTerminateProcess(response, holder);
                return;
            }
            holder.setCallbacks(null);
        } else {
            final ReplyMessageAttribute msg = getNextCallbackReplyMsg(response, holder);
            if (msg == null) {
                // failed to inject and already sent a reject msg so stop processing at this point.
                return;
            }
            // if we get here then we have a challenge response message ready to send
            final AccessChallenge challenge = new AccessChallenge();
            if (state == null) {
                // as when starting authentication
                state = new StateAttribute(holder.getCacheKey());
            }
            challenge.addAttribute(state);
            challenge.addAttribute(msg);
            response.setResponsePacket(challenge);
            // exit out and await response to challenge response
            return;
        }
    }
}
Also used : StateAttribute(org.forgerock.openam.radius.common.StateAttribute) ReplyMessageAttribute(org.forgerock.openam.radius.common.ReplyMessageAttribute) PagePropertiesCallback(com.sun.identity.authentication.spi.PagePropertiesCallback) HttpCallback(com.sun.identity.authentication.spi.HttpCallback) RedirectCallback(com.sun.identity.authentication.spi.RedirectCallback) PasswordCallback(javax.security.auth.callback.PasswordCallback) ChoiceCallback(javax.security.auth.callback.ChoiceCallback) NameCallback(javax.security.auth.callback.NameCallback) ConfirmationCallback(javax.security.auth.callback.ConfirmationCallback) Callback(javax.security.auth.callback.Callback) AccessChallenge(org.forgerock.openam.radius.common.AccessChallenge)

Example 4 with StateAttribute

use of org.forgerock.openam.radius.common.StateAttribute in project OpenAM by OpenRock.

the class RadiusConn method replyChallenge.

/**
     * Sends an access-request to the server in response to a challenge request.
     *
     * @param name     the username.
     * @param password the password.
     * @param ce       the challenge exception providing access to the original challenge response.
     * @throws IOException              if there is a problem.
     * @throws NoSuchAlgorithmException if there is a problem.
     * @throws RejectException          if there is a problem.
     * @throws ChallengeException       if there is a problem.
     */
public void replyChallenge(String name, String password, ChallengeException ce) throws IOException, NoSuchAlgorithmException, RejectException, ChallengeException {
    StateAttribute state = (StateAttribute) ce.getAttributeSet().getAttributeByType(AttributeType.STATE);
    if (state == null) {
        throw new IOException("State not found in challenge");
    }
    AccessRequest req = createAccessRequest();
    // needed in challenge
    req.addAttribute(state);
    if (name != null) {
        req.addAttribute(new UserNameAttribute(name));
    }
    req.addAttribute(new UserPasswordAttribute(req.getAuthenticator(), secret, password));
    req.addAttribute(new NASIPAddressAttribute(InetAddress.getLocalHost()));
    req.addAttribute(new NASPortAttribute(socket.getLocalPort()));
    sendPacket(req);
}
Also used : StateAttribute(org.forgerock.openam.radius.common.StateAttribute) AccessRequest(org.forgerock.openam.radius.common.AccessRequest) UserNameAttribute(org.forgerock.openam.radius.common.UserNameAttribute) NASPortAttribute(org.forgerock.openam.radius.common.packet.NASPortAttribute) IOException(java.io.IOException) NASIPAddressAttribute(org.forgerock.openam.radius.common.packet.NASIPAddressAttribute) UserPasswordAttribute(org.forgerock.openam.radius.common.UserPasswordAttribute)

Aggregations

StateAttribute (org.forgerock.openam.radius.common.StateAttribute)4 IOException (java.io.IOException)3 UserNameAttribute (org.forgerock.openam.radius.common.UserNameAttribute)3 UserPasswordAttribute (org.forgerock.openam.radius.common.UserPasswordAttribute)3 AccessChallenge (org.forgerock.openam.radius.common.AccessChallenge)2 AccessRequest (org.forgerock.openam.radius.common.AccessRequest)2 ReplyMessageAttribute (org.forgerock.openam.radius.common.ReplyMessageAttribute)2 NASIPAddressAttribute (org.forgerock.openam.radius.common.packet.NASIPAddressAttribute)2 NASPortAttribute (org.forgerock.openam.radius.common.packet.NASPortAttribute)2 HttpCallback (com.sun.identity.authentication.spi.HttpCallback)1 PagePropertiesCallback (com.sun.identity.authentication.spi.PagePropertiesCallback)1 RedirectCallback (com.sun.identity.authentication.spi.RedirectCallback)1 InetSocketAddress (java.net.InetSocketAddress)1 ByteBuffer (java.nio.ByteBuffer)1 DatagramChannel (java.nio.channels.DatagramChannel)1 SecureRandom (java.security.SecureRandom)1 Callback (javax.security.auth.callback.Callback)1 ChoiceCallback (javax.security.auth.callback.ChoiceCallback)1 ConfirmationCallback (javax.security.auth.callback.ConfirmationCallback)1 NameCallback (javax.security.auth.callback.NameCallback)1