Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Sign in / Register
Toggle navigation
N
Node Radius Server
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Locked Files
Issues
0
Issues
0
List
Boards
Labels
Service Desk
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Security & Compliance
Security & Compliance
Dependency List
License Compliance
Packages
Packages
List
Container Registry
Analytics
Analytics
CI / CD
Code Review
Insights
Issues
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
nanahira
Node Radius Server
Commits
6aa4b9f9
Commit
6aa4b9f9
authored
Feb 24, 2020
by
simon
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
feat: inner tunnel for TTSL support added
parent
191bb542
Changes
13
Expand all
Hide whitespace changes
Inline
Side-by-side
Showing
13 changed files
with
419 additions
and
136 deletions
+419
-136
src/auth.ts
src/auth.ts
+1
-0
src/auth/GoogleLDAPAuth.ts
src/auth/GoogleLDAPAuth.ts
+1
-1
src/radius/RadiusService.ts
src/radius/RadiusService.ts
+11
-1
src/radius/handler/EAPPacketHandler.ts
src/radius/handler/EAPPacketHandler.ts
+9
-91
src/radius/handler/eap/EAPHelper.ts
src/radius/handler/eap/EAPHelper.ts
+79
-0
src/radius/handler/eap/eapMethods/EAP-GTC.ts
src/radius/handler/eap/eapMethods/EAP-GTC.ts
+65
-0
src/radius/handler/eap/eapMethods/EAP-MD5.ts
src/radius/handler/eap/eapMethods/EAP-MD5.ts
+40
-0
src/radius/handler/eap/eapMethods/EAP-TTLS.ts
src/radius/handler/eap/eapMethods/EAP-TTLS.ts
+204
-39
src/radius/handler/eap/eapMethods/EAP.ts
src/radius/handler/eap/eapMethods/EAP.ts
+0
-0
src/radius/handler/eap/eapMethods/challenges/PAPChallenge.ts
src/radius/handler/eap/eapMethods/challenges/PAPChallenge.ts
+1
-1
src/tls/crypt.ts
src/tls/crypt.ts
+6
-1
src/types/EAPChallenge.ts
src/types/EAPChallenge.ts
+1
-1
src/types/EAPMethod.ts
src/types/EAPMethod.ts
+1
-1
No files found.
src/auth.ts
View file @
6aa4b9f9
...
...
@@ -18,6 +18,7 @@ export class Authentication implements IAuthentication {
}
const
authResult
=
await
this
.
authenticator
.
authenticate
(
username
,
password
);
console
.
log
(
`Auth Result for user
${
username
}
`
,
authResult
?
'
SUCCESS
'
:
'
Failure
'
);
this
.
cache
.
set
(
cacheKey
,
authResult
,
86400
);
// cache for one day
return
authResult
;
...
...
src/auth/GoogleLDAPAuth.ts
View file @
6aa4b9f9
...
...
@@ -113,7 +113,7 @@ export class GoogleLDAPAuth implements IAuthentication {
if (!dnsFetched && !forceFetching) {
return this.authenticate(username, password, count, true);
}
console.error(`
invalid
username
,
not
found
in
DN
:
$
{
username
}
`
,
this
.
allValidDNsCache
);
console.error(`
invalid
username
,
not
found
in
DN
:
$
{
username
}
`
);
//
, this.allValidDNsCache);
return
false
;
}
...
...
src/radius/RadiusService.ts
View file @
6aa4b9f9
...
...
@@ -4,11 +4,21 @@ import { EAPPacketHandler } from './handler/EAPPacketHandler';
import
{
DefaultPacketHandler
}
from
'
./handler/DefaultPacketHandler
'
;
import
{
IPacketHandler
,
IPacketHandlerResult
,
PacketResponseCode
}
from
'
../types/PacketHandler
'
;
import
{
EAPTTLS
}
from
'
./handler/eap/eapMethods/EAP-TTLS
'
;
import
{
EAPMD5
}
from
'
./handler/eap/eapMethods/EAP-MD5
'
;
import
{
EAPGTC
}
from
'
./handler/eap/eapMethods/EAP-GTC
'
;
export
class
RadiusService
{
radiusPacketHandlers
:
IPacketHandler
[]
=
[];
constructor
(
private
secret
:
string
,
private
authentication
:
IAuthentication
)
{
this
.
radiusPacketHandlers
.
push
(
new
EAPPacketHandler
(
authentication
));
this
.
radiusPacketHandlers
.
push
(
new
EAPPacketHandler
([
new
EAPTTLS
(
authentication
),
new
EAPGTC
(
authentication
),
new
EAPMD5
(
authentication
)
])
);
this
.
radiusPacketHandlers
.
push
(
new
DefaultPacketHandler
(
authentication
));
}
...
...
src/radius/handler/EAPPacketHandler.ts
View file @
6aa4b9f9
...
...
@@ -3,103 +3,21 @@
import
*
as
NodeCache
from
'
node-cache
'
;
import
{
RadiusPacket
}
from
'
radius
'
;
import
debug
from
'
debug
'
;
import
{
EAPTTLS
}
from
'
./eapMethods/EAPTTLS
'
;
import
{
makeid
}
from
'
../../helpers
'
;
import
{
IPacketHandler
,
IPacketHandlerResult
,
PacketResponseCode
}
from
'
../../types/PacketHandler
'
;
import
{
IAuthentication
}
from
'
../../types/Authentication
'
;
import
{
IPacketHandler
,
IPacketHandlerResult
}
from
'
../../types/PacketHandler
'
;
import
{
IEAPMethod
}
from
'
../../types/EAPMethod
'
;
import
{
buildEAPResponse
,
decodeEAPHeader
}
from
'
./eap/EAPHelper
'
;
const
log
=
debug
(
'
radius:eap
'
);
export
class
EAPPacketHandler
implements
IPacketHandler
{
private
eapMethods
:
IEAPMethod
[]
=
[];
// private eapConnectionStates: { [key: string]: { validMethods: IEAPMethod[] } } = {};
private
eapConnectionStates
=
new
NodeCache
({
useClones
:
false
,
stdTTL
:
3600
});
// max for one hour
constructor
(
authentication
:
IAuthentication
)
{
this
.
eapMethods
.
push
(
new
EAPTTLS
(
authentication
));
}
/**
*
* @param data
* @param msgType 1 = identity, 21 = EAP-TTLS, 2 = notification, 4 = md5-challenge, 3 = NAK
*/
private
async
buildEAPResponse
(
identifier
:
number
,
msgType
:
number
,
data
?:
Buffer
):
Promise
<
IPacketHandlerResult
>
{
/** build a package according to this:
0 1 2 3
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Code | Identifier | Length |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Type | Type-Data ...
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-
*/
const
buffer
=
Buffer
.
from
([
1
,
// request
identifier
,
0
,
// length (1/2)
0
,
// length (2/2)
msgType
// 1 = identity, 21 = EAP-TTLS, 2 = notificaiton, 4 = md5-challenge, 3 = NAK
]);
const
resBuffer
=
data
?
Buffer
.
concat
([
buffer
,
data
])
:
buffer
;
// set EAP length header
resBuffer
.
writeUInt16BE
(
resBuffer
.
byteLength
,
2
);
return
{
code
:
PacketResponseCode
.
AccessChallenge
,
attributes
:
[[
'
EAP-Message
'
,
buffer
]]
};
}
private
decodeEAPHeader
(
msg
:
Buffer
)
{
/**
* parse msg according to this:
0 1 2 3
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Code | Identifier | Length |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Type | Type-Data ...
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-
*/
/*
code:
1 Request
2 Response
3 Success
4 Failure
*/
const
code
=
msg
.
slice
(
0
,
1
).
readUInt8
(
0
);
/* identifier is a number */
const
identifier
=
msg
.
slice
(
1
,
2
).
readUInt8
(
0
);
const
length
=
msg
.
slice
(
2
,
4
).
readInt16BE
(
0
);
/* EAP type */
const
type
=
msg
.
slice
(
4
,
5
).
readUInt8
(
0
);
const
data
=
msg
.
slice
(
5
);
return
{
code
,
identifier
,
length
,
type
,
data
};
}
constructor
(
private
eapMethods
:
IEAPMethod
[])
{}
async
handlePacket
(
attributes
:
{
[
key
:
string
]:
Buffer
},
attributes
:
{
[
key
:
string
]:
Buffer
|
string
},
orgRadiusPacket
:
RadiusPacket
):
Promise
<
IPacketHandlerResult
>
{
if
(
!
attributes
[
'
EAP-Message
'
])
{
...
...
@@ -116,9 +34,9 @@ export class EAPPacketHandler implements IPacketHandler {
}
// EAP MESSAGE
const
msg
=
attributes
[
'
EAP-Message
'
];
const
msg
=
attributes
[
'
EAP-Message
'
]
as
Buffer
;
const
{
code
,
type
,
identifier
,
data
}
=
this
.
decodeEAPHeader
(
msg
);
const
{
code
,
type
,
identifier
,
data
}
=
decodeEAPHeader
(
msg
);
const
currentState
=
this
.
eapConnectionStates
.
get
(
stateID
)
as
{
validMethods
:
IEAPMethod
[]
};
...
...
@@ -130,10 +48,10 @@ export class EAPPacketHandler implements IPacketHandler {
log
(
'
>>>>>>>>>>>> REQUEST FROM CLIENT: IDENTIFY
'
,
{});
// start identify
if
(
currentState
.
validMethods
.
length
>
0
)
{
return
currentState
.
validMethods
[
0
].
identify
(
identifier
,
stateID
);
return
currentState
.
validMethods
[
0
].
identify
(
identifier
,
stateID
,
data
);
}
return
this
.
buildEAPResponse
(
identifier
,
3
);
return
buildEAPResponse
(
identifier
,
3
);
// NAK
case
2
:
// notification
log
(
'
>>>>>>>>>>>> REQUEST FROM CLIENT: notification
'
,
{});
console
.
info
(
'
notification
'
);
...
...
@@ -180,7 +98,7 @@ export class EAPPacketHandler implements IPacketHandler {
console
.
error
(
'
unsupported type
'
,
type
,
`requesting:
${
serverSupportedMethods
}
`
);
return
this
.
buildEAPResponse
(
identifier
,
3
,
Buffer
.
from
(
serverSupportedMethods
));
return
buildEAPResponse
(
identifier
,
3
,
Buffer
.
from
(
serverSupportedMethods
));
}
}
break
;
...
...
src/radius/handler/eap/EAPHelper.ts
0 → 100644
View file @
6aa4b9f9
import
{
IPacketHandlerResult
,
PacketResponseCode
}
from
'
../../../types/PacketHandler
'
;
export
function
buildEAP
(
identifier
:
number
,
msgType
:
number
,
data
?:
Buffer
)
{
/** build a package according to this:
0 1 2 3
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Code | Identifier | Length |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Type | Type-Data ...
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-
*/
const
buffer
=
Buffer
.
from
([
1
,
// request
identifier
,
0
,
// length (1/2)
0
,
// length (2/2)
msgType
// 1 = identity, 21 = EAP-TTLS, 2 = notificaiton, 4 = md5-challenge, 3 = NAK
]);
const
resBuffer
=
data
?
Buffer
.
concat
([
buffer
,
data
])
:
buffer
;
// set EAP length header
resBuffer
.
writeUInt16BE
(
resBuffer
.
byteLength
,
2
);
return
resBuffer
;
}
/**
*
* @param data
* @param msgType 1 = identity, 21 = EAP-TTLS, 2 = notification, 4 = md5-challenge, 3 = NAK
*/
export
function
buildEAPResponse
(
identifier
:
number
,
msgType
:
number
,
data
?:
Buffer
):
IPacketHandlerResult
{
return
{
code
:
PacketResponseCode
.
AccessChallenge
,
attributes
:
[[
'
EAP-Message
'
,
buildEAP
(
identifier
,
msgType
,
data
)]]
};
}
export
function
decodeEAPHeader
(
msg
:
Buffer
)
{
/**
* parse msg according to this:
0 1 2 3
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Code | Identifier | Length |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Type | Type-Data ...
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-
*/
/*
code:
1 Request
2 Response
3 Success
4 Failure
*/
const
code
=
msg
.
slice
(
0
,
1
).
readUInt8
(
0
);
/* identifier is a number */
const
identifier
=
msg
.
slice
(
1
,
2
).
readUInt8
(
0
);
const
length
=
msg
.
slice
(
2
,
4
).
readUInt16BE
(
0
);
/* EAP type */
const
type
=
msg
.
slice
(
4
,
5
).
readUInt8
(
0
);
const
data
=
msg
.
slice
(
5
);
return
{
code
,
identifier
,
length
,
type
,
data
};
}
src/radius/handler/eap/eapMethods/EAP-GTC.ts
0 → 100644
View file @
6aa4b9f9
// https://tools.ietf.org/html/rfc5281 TTLS v0
// https://tools.ietf.org/html/draft-funk-eap-ttls-v1-00 TTLS v1 (not implemented)
/* eslint-disable no-bitwise */
import
*
as
NodeCache
from
'
node-cache
'
;
import
debug
from
'
debug
'
;
import
{
IPacketHandlerResult
,
PacketResponseCode
}
from
'
../../../../types/PacketHandler
'
;
import
{
IEAPMethod
}
from
'
../../../../types/EAPMethod
'
;
import
{
IAuthentication
}
from
'
../../../../types/Authentication
'
;
import
{
buildEAPResponse
,
decodeEAPHeader
}
from
'
../EAPHelper
'
;
const
log
=
debug
(
'
radius:eap:gtc
'
);
export
class
EAPGTC
implements
IEAPMethod
{
private
loginData
=
new
NodeCache
({
useClones
:
false
,
stdTTL
:
60
});
// queue data maximum for 60 seconds
getEAPType
():
number
{
return
6
;
}
identify
(
identifier
:
number
,
stateID
:
string
,
msg
?:
Buffer
):
IPacketHandlerResult
{
if
(
msg
)
{
const
parsedMsg
=
msg
.
slice
(
0
,
msg
.
findIndex
(
v
=>
v
===
0
)
);
log
(
'
identify
'
,
parsedMsg
,
parsedMsg
.
toString
());
this
.
loginData
.
set
(
stateID
,
parsedMsg
);
// use token til binary 0.);
}
else
{
log
(
'
no msg
'
);
}
return
buildEAPResponse
(
identifier
,
6
,
Buffer
.
from
(
'
Password:
'
));
}
constructor
(
private
authentication
:
IAuthentication
)
{}
async
handleMessage
(
_identifier
:
number
,
stateID
:
string
,
msg
:
Buffer
):
Promise
<
IPacketHandlerResult
>
{
const
username
=
this
.
loginData
.
get
(
stateID
)
as
Buffer
|
undefined
;
const
{
data
}
=
decodeEAPHeader
(
msg
);
let
tillBinary0
=
data
.
findIndex
(
v
=>
v
===
0
)
||
data
.
length
;
if
(
tillBinary0
<
0
)
{
tillBinary0
=
data
.
length
-
1
;
}
const
token
=
data
.
slice
(
0
,
tillBinary0
+
1
);
// use token til binary 0.
if
(
!
username
)
{
throw
new
Error
(
'
no username
'
);
}
log
(
'
username
'
,
username
,
username
.
toString
());
log
(
'
token
'
,
token
,
token
.
toString
());
const
success
=
await
this
.
authentication
.
authenticate
(
username
.
toString
(),
token
.
toString
());
return
{
code
:
success
?
PacketResponseCode
.
AccessAccept
:
PacketResponseCode
.
AccessReject
};
}
}
src/radius/handler/eap/eapMethods/EAP-MD5.ts
0 → 100644
View file @
6aa4b9f9
// https://tools.ietf.org/html/rfc5281 TTLS v0
// https://tools.ietf.org/html/draft-funk-eap-ttls-v1-00 TTLS v1 (not implemented)
/* eslint-disable no-bitwise */
import
{
RadiusPacket
}
from
'
radius
'
;
import
debug
from
'
debug
'
;
import
{
ResponseAuthHandler
}
from
'
../../../../types/Handler
'
;
import
{
IPacketHandlerResult
}
from
'
../../../../types/PacketHandler
'
;
import
{
IEAPMethod
}
from
'
../../../../types/EAPMethod
'
;
import
{
IAuthentication
}
from
'
../../../../types/Authentication
'
;
const
log
=
debug
(
'
radius:eap:md5
'
);
interface
IEAPResponseHandlers
{
response
:
(
respData
?:
Buffer
,
msgType
?:
number
)
=>
void
;
checkAuth
:
ResponseAuthHandler
;
}
export
class
EAPMD5
implements
IEAPMethod
{
getEAPType
():
number
{
return
4
;
}
identify
(
_identifier
:
number
,
_stateID
:
string
):
IPacketHandlerResult
{
// NOT IMPLEMENTED
return
{};
}
constructor
(
private
authentication
:
IAuthentication
)
{}
async
handleMessage
(
_identifier
:
number
,
_stateID
:
string
,
_msg
:
Buffer
,
_orgRadiusPacket
:
RadiusPacket
):
Promise
<
IPacketHandlerResult
>
{
// not implemented
return
{};
}
}
src/radius/handler/eap
Methods/EAP
TTLS.ts
→
src/radius/handler/eap
/eapMethods/EAP-
TTLS.ts
View file @
6aa4b9f9
This diff is collapsed.
Click to expand it.
src/radius/handler/eap/eapMethods/EAP.ts
0 → 100644
View file @
6aa4b9f9
src/radius/handler/eapMethods/challenges/PAPChallenge.ts
→
src/radius/handler/eap
/eap
Methods/challenges/PAPChallenge.ts
View file @
6aa4b9f9
import
debug
from
'
debug
'
;
import
{
IEAPChallenge
}
from
'
../../../../types/EAPChallenge
'
;
import
{
IEAPChallenge
}
from
'
../../../../
../
types/EAPChallenge
'
;
const
log
=
debug
(
'
radius:eap:papchallenge
'
);
...
...
src/tls/crypt.ts
View file @
6aa4b9f9
...
...
@@ -42,11 +42,16 @@ export function startTLSServer(): ITLSServer {
});
const
encrypted
=
duplexpair
.
socket2
;
emitter
.
on
(
'
send
'
,
(
data
:
Buffer
)
=>
{
emitter
.
on
(
'
decrypt
'
,
(
data
:
Buffer
)
=>
{
encrypted
.
write
(
data
);
// encrypted.sync();
});
emitter
.
on
(
'
encrypt
'
,
(
data
:
Buffer
)
=>
{
cleartext
.
write
(
data
);
// encrypted.sync();
});
encrypted
.
on
(
'
data
'
,
(
data
:
Buffer
)
=>
{
// log('encrypted data', data, data.toString());
emitter
.
emit
(
'
response
'
,
data
);
...
...
src/types/EAPChallenge.ts
View file @
6aa4b9f9
export
interface
IEAPChallenge
{
decode
(
data
:
Buffer
):
{
username
:
string
;
password
:
string
};
decode
(
data
:
Buffer
,
stateID
:
string
):
{
username
:
string
;
password
?
:
string
};
}
src/types/EAPMethod.ts
View file @
6aa4b9f9
...
...
@@ -4,7 +4,7 @@ import { IPacketHandlerResult } from './PacketHandler';
export
interface
IEAPMethod
{
getEAPType
():
number
;
identify
(
identifier
:
number
,
stateID
:
string
):
IPacketHandlerResult
;
identify
(
identifier
:
number
,
stateID
:
string
,
msg
?:
Buffer
):
IPacketHandlerResult
;
handleMessage
(
identifier
:
number
,
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment