001/* 002 * Licensed to the Apache Software Foundation (ASF) under one 003 * or more contributor license agreements. See the NOTICE file 004 * distributed with this work for additional information 005 * regarding copyright ownership. The ASF licenses this file 006 * to you under the Apache License, Version 2.0 (the 007 * "License"); you may not use this file except in compliance 008 * with the License. You may obtain a copy of the License at 009 * 010 * http://www.apache.org/licenses/LICENSE-2.0 011 * 012 * Unless required by applicable law or agreed to in writing, 013 * software distributed under the License is distributed on an 014 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 015 * KIND, either express or implied. See the License for the 016 * specific language governing permissions and limitations 017 * under the License. 018 * 019 */ 020package org.apache.mina.example.tapedeck; 021 022import static org.apache.mina.statemachine.event.IoFilterEvents.*; 023 024import org.apache.mina.core.filterchain.IoFilter.NextFilter; 025import org.apache.mina.core.future.IoFutureListener; 026import org.apache.mina.core.session.IoSession; 027import org.apache.mina.core.write.WriteRequest; 028import org.apache.mina.example.tapedeck.TapeDeckServer.TapeDeckContext; 029import org.apache.mina.statemachine.StateControl; 030import org.apache.mina.statemachine.annotation.IoFilterTransition; 031import org.apache.mina.statemachine.annotation.State; 032import org.apache.mina.statemachine.context.AbstractStateContext; 033 034/** 035 * TODO Add documentation 036 * 037 * @author <a href="http://mina.apache.org">Apache MINA Project</a> 038 */ 039public class AuthenticationHandler { 040 @State public static final String ROOT = "Root"; 041 @State(ROOT) public static final String START = "Start"; 042 @State(ROOT) public static final String WAIT_USER = "WaitUser"; 043 @State(ROOT) public static final String WAIT_PASSWORD = "WaitPassword"; 044 @State(ROOT) public static final String DONE = "Done"; 045 @State(ROOT) public static final String FAILED = "Failed"; 046 047 static class AuthenticationContext extends AbstractStateContext { 048 private String user; 049 private String password; 050 private int tries = 0; 051 } 052 053 @IoFilterTransition(on = SESSION_OPENED, in = START, next = WAIT_USER) 054 public void sendAuthRequest(NextFilter nextFilter, IoSession session) { 055 session.write("+ Greetings from your tape deck!. Please authenticate yourself."); 056 } 057 058 @IoFilterTransition(on = MESSAGE_RECEIVED, in = WAIT_USER, next = WAIT_PASSWORD) 059 public void user(AuthenticationContext context, NextFilter nextFilter, IoSession session, UserCommand cmd) { 060 context.user = cmd.getUsername(); 061 session.write("+ Give me your password (hint: try your username backwards)"); 062 } 063 064 @IoFilterTransition(on = MESSAGE_RECEIVED, in = WAIT_PASSWORD, next = DONE) 065 public void password(AuthenticationContext context, NextFilter nextFilter, IoSession session, PasswordCommand cmd) { 066 context.password = cmd.getPassword(); 067 if (context.password.equals(reverse(context.user))) { 068 session.write("+ Authentication succeeded! Your tape deck has been unlocked."); 069 } else { 070 context.tries++; 071 if (context.tries < 3) { 072 session.write("- Authentication failed! Please try again."); 073 StateControl.breakAndGotoNext(WAIT_USER); 074 } else { 075 session.write("- Authentication failed too many times! Bye bye.").addListener(IoFutureListener.CLOSE); 076 StateControl.breakAndGotoNext(FAILED); 077 } 078 } 079 } 080 081 082 @IoFilterTransition(on = MESSAGE_RECEIVED, in = ROOT) 083 public void quit(TapeDeckContext context, IoSession session, QuitCommand cmd) { 084 session.write("+ Bye! Please come back!").addListener(IoFutureListener.CLOSE); 085 } 086 087 private String reverse(String s) { 088 char[] expectedPassword = new char[s.length()]; 089 for (int i = 0; i < expectedPassword.length; i++) { 090 expectedPassword[i] = s.charAt(s.length() - i - 1); 091 } 092 return new String(expectedPassword); 093 } 094 095 @IoFilterTransition(on = MESSAGE_RECEIVED, in = WAIT_USER, weight = 10) 096 public void errorWaitingForUser(IoSession session, Command cmd) { 097 if (cmd instanceof QuitCommand) { 098 StateControl.breakAndContinue(); 099 } 100 session.write("Unexpected command '" + cmd.getName() + "'. Expected 'user <username>'."); 101 } 102 103 @IoFilterTransition(on = MESSAGE_RECEIVED, in = WAIT_PASSWORD, weight = 10) 104 public void errorWaitingForPassword(IoSession session, Command cmd) { 105 if (cmd instanceof QuitCommand) { 106 StateControl.breakAndContinue(); 107 } 108 session.write("Unexpected command '" + cmd.getName() + "'. Expected 'password <password>'."); 109 } 110 111 @IoFilterTransition(on = EXCEPTION_CAUGHT, in = ROOT) 112 public void commandSyntaxError(IoSession session, CommandSyntaxException e) { 113 session.write("- " + e.getMessage()); 114 } 115 116 @IoFilterTransition(on = EXCEPTION_CAUGHT, in = ROOT, weight = 10) 117 public void exceptionCaught(IoSession session, Exception e) { 118 e.printStackTrace(); 119 session.closeNow(); 120 } 121 122 @IoFilterTransition(on = SESSION_CLOSED, in = DONE) 123 public void sessionClosed(NextFilter nextFilter, IoSession session) { 124 nextFilter.sessionClosed(session); 125 } 126 @IoFilterTransition(on = EXCEPTION_CAUGHT, in = DONE) 127 public void exceptionCaught(NextFilter nextFilter, IoSession session, Throwable cause) { 128 nextFilter.exceptionCaught(session, cause); 129 } 130 @IoFilterTransition(on = MESSAGE_RECEIVED, in = DONE) 131 public void messageReceived(NextFilter nextFilter, IoSession session, Object message) { 132 nextFilter.messageReceived(session, message); 133 } 134 @IoFilterTransition(on = MESSAGE_SENT, in = DONE) 135 public void messageSent(NextFilter nextFilter, IoSession session, WriteRequest writeRequest) { 136 nextFilter.messageSent(session, writeRequest); 137 } 138 139 @IoFilterTransition(on = CLOSE, in = ROOT) 140 public void filterClose(NextFilter nextFilter, IoSession session) { 141 nextFilter.filterClose(session); 142 } 143 @IoFilterTransition(on = WRITE, in = ROOT) 144 public void filterWrite(NextFilter nextFilter, IoSession session, WriteRequest writeRequest) { 145 nextFilter.filterWrite(session, writeRequest); 146 } 147}