github.com/keysonZZZ/kmg@v0.0.0-20151121023212-05317bfd7d39/third/kmgRadius/Auth.go (about)

     1  package kmgRadius
     2  
     3  import (
     4  	"crypto/rand"
     5  	"fmt"
     6  
     7  	. "github.com/bronze1man/kmg/kmgErr"
     8  	"github.com/bronze1man/kmg/kmgLog"
     9  	"github.com/bronze1man/kmg/kmgRand"
    10  	"github.com/bronze1man/kmg/third/kmgRadius/MSCHAPV2"
    11  	"github.com/bronze1man/kmg/third/kmgRadius/eap"
    12  )
    13  
    14  // 目前支持pap和mschapv2认证方式
    15  func (p *server) radiusAccess(request *Packet) *Packet {
    16  	kmgLog.Log("Radius", "Access Request", request.ToStringMap())
    17  	npac := request.Reply()
    18  
    19  	username := request.GetUsername()
    20  	password := request.GetPassword()
    21  	if username == "" {
    22  		//不支持的认证方式,或者包格式错误
    23  		npac.AVPs = append(npac.AVPs, &StringAVP{Type: AVPTypeReplyMessage, Value: "need username"})
    24  		npac.Code = CodeAccessReject
    25  		LogError(fmt.Errorf("[kmgRadius.radiusAccess] need username or auth method not support"))
    26  		return npac
    27  	}
    28  	AuthPassword, exist := p.handler.Auth(username)
    29  	if !exist {
    30  		LogError(fmt.Errorf("[kmgRadius.radiusAccess] username [%s] not exist or do not have any transfer", username))
    31  		npac.Code = CodeAccessReject
    32  		return npac
    33  	}
    34  	//简单认证方式 pap
    35  	if password != "" {
    36  		if AuthPassword != password {
    37  			LogError(fmt.Errorf("[kmgRadius.radiusAccess] username [%s] password not match", username))
    38  			npac.Code = CodeAccessReject
    39  			return npac
    40  		}
    41  		npac.Code = CodeAccessAccept
    42  		return npac
    43  	}
    44  	//复杂认证方式
    45  	//如果没有输入密码,要求用户输入密码(遗留代码,应该是之前的bug导致的)
    46  	e := request.GetEAPMessage()
    47  	if e != nil {
    48  		//第一次请求,eapCode应该是 Response
    49  		// mschapv2 step 1
    50  		switch e.Header().Type {
    51  		case eap.TypeIdentity, eap.TypeLegacyNak:
    52  			npac.Code = CodeAccessChallenge
    53  			mschapV2Challenge := [16]byte{}
    54  			_, err := rand.Read(mschapV2Challenge[:])
    55  			if err != nil {
    56  				panic(err)
    57  			}
    58  			sessionId := kmgRand.MustCryptoRandToAlphaNum(18)
    59  			npac.SetState([]byte(sessionId))
    60  
    61  			p.mschapMap[sessionId] = mschapStatus{
    62  				Challenge: mschapV2Challenge,
    63  			}
    64  			npac.AddAVP(&EapAVP{
    65  				Value: &eap.MSCHAPV2Packet{
    66  					PacketHeader: eap.PacketHeader{
    67  						Code:       eap.CodeRequest,
    68  						Identifier: e.Header().Identifier,
    69  						Type:       eap.TypeMSCHAPV2,
    70  					},
    71  					MSCHAPV2: &MSCHAPV2.ChallengePacket{
    72  						Identifier: e.Header().Identifier,
    73  						Challenge:  mschapV2Challenge,
    74  						Name:       username,
    75  					},
    76  				},
    77  			})
    78  			return npac
    79  		//TODO process next step read Response packet and write Success Request packet
    80  		// reference http://tools.ietf.org/id/draft-kamath-pppext-eap-mschapv2-01.txt
    81  		case eap.TypeMSCHAPV2:
    82  			// mschapv2 step 3 and step 5
    83  			if e.Header().Code != eap.CodeResponse {
    84  				npac.Code = CodeAccessReject
    85  				LogError(fmt.Errorf("MSCHAPV2 step 3 fail! 1 eap.Code[%s]!=radius.EapCodeResponse", e.Header().Code))
    86  				return npac
    87  			}
    88  			mschapv2I := e.(*eap.MSCHAPV2Packet).MSCHAPV2
    89  			switch mschapv2I.OpCode() {
    90  			case MSCHAPV2.OpCodeResponse:
    91  				state := request.GetState()
    92  				//step 3
    93  				status, ok := p.mschapMap[string(state)]
    94  				if !ok {
    95  					npac.Code = CodeAccessReject
    96  					LogError(fmt.Errorf("MSCHAPV2 step 3 fail! 3 mschapStatus not found state:%s", state))
    97  					return npac
    98  				}
    99  				status.NTResponse = mschapv2I.(*MSCHAPV2.ResponsePacket).NTResponse
   100  				p.mschapMap[string(state)] = status
   101  				successPacket := MSCHAPV2.ReplySuccessPacket(&MSCHAPV2.ReplySuccessPacketRequest{
   102  					AuthenticatorChallenge: status.Challenge,
   103  					Response:               mschapv2I.(*MSCHAPV2.ResponsePacket),
   104  					Username:               []byte(username),
   105  					Password:               []byte(AuthPassword),
   106  					Message:                "success",
   107  				})
   108  				npac.AddAVP(&EapAVP{
   109  					Value: &eap.MSCHAPV2Packet{
   110  						PacketHeader: eap.PacketHeader{
   111  							Code:       eap.CodeRequest,
   112  							Identifier: e.Header().Identifier,
   113  							Type:       eap.TypeMSCHAPV2,
   114  						},
   115  						MSCHAPV2: successPacket,
   116  					},
   117  				})
   118  				npac.Code = CodeAccessChallenge
   119  				return npac
   120  			case MSCHAPV2.OpCodeSuccess:
   121  				//step 5
   122  				// reference http://www.ietf.org/rfc/rfc3079.txt
   123  				state := request.GetState()
   124  				//step 3
   125  				status, ok := p.mschapMap[string(state)]
   126  				if !ok {
   127  					npac.Code = CodeAccessReject
   128  					LogError(fmt.Errorf("MSCHAPV2 step 5 fail! 5 mschapStatus not found state:%#v", state))
   129  					return npac
   130  				}
   131  
   132  				npac.AddAVP(&EapAVP{
   133  					Value: &eap.SimplePacket{
   134  						PacketHeader: eap.PacketHeader{
   135  							Code:       eap.CodeSuccess,
   136  							Identifier: e.Header().Identifier,
   137  						},
   138  					},
   139  				})
   140  				npac.AddAVP(&StringAVP{
   141  					Type:  AVPTypeUserName,
   142  					Value: username,
   143  				})
   144  				//MS-MPPE-Encryption-Policy: Encryption-Allowed (1)
   145  				npac.AddAVP(&BinaryAVP{
   146  					Type:  AVPTypeVendorSpecific,
   147  					Value: []byte{0x00, 0x00, 0x01, 0x37, 0x07, 0x06, 0, 0, 0, 1},
   148  				})
   149  				//MS-MPPE-Encryption-Types: RC4-40-128 (6)
   150  				npac.AddAVP(&BinaryAVP{
   151  					Type:  AVPTypeVendorSpecific,
   152  					Value: []byte{0x00, 0x00, 0x01, 0x37, 0x08, 0x06, 0, 0, 0, 6},
   153  				})
   154  				sendkey, recvKey := MSCHAPV2.MsCHAPV2GetSendAndRecvKey([]byte(AuthPassword), status.NTResponse)
   155  				npac.AddAVP(&VendorSpecificAVP{
   156  					Value: NewMSMPPESendOrRecvKeyVSA(request, VendorTypeMSMPPESendKey, sendkey),
   157  				})
   158  				npac.AddAVP(&VendorSpecificAVP{
   159  					Value: NewMSMPPESendOrRecvKeyVSA(request, VendorTypeMSMPPERecvKey, recvKey),
   160  				})
   161  				npac.Code = CodeAccessAccept
   162  				npac.DeleteOneType(AVPTypeState)
   163  				return npac
   164  			default:
   165  				npac.Code = CodeAccessReject
   166  				LogError(fmt.Errorf("MSCHAPV2 step 3 and 5 fail! 2.5 mschapv2I.OpCode()[%s]!= MSCHAPV2.OpCodeResponse",
   167  					mschapv2I.OpCode()))
   168  				return npac
   169  			}
   170  		default:
   171  			npac.Code = CodeAccessReject
   172  			LogError(fmt.Errorf("MSCHAPV2 eap fail! 4"))
   173  			return npac
   174  		}
   175  	}
   176  	//不支持的认证方式,或者包格式错误
   177  	npac.AVPs = append(npac.AVPs, &StringAVP{Type: AVPTypeReplyMessage, Value: "need password"})
   178  	npac.Code = CodeAccessReject
   179  	LogError(fmt.Errorf("[kmgRadius.radiusAccess] username[%s] need password or auth method not support", username))
   180  	return npac
   181  }