diff --git a/gb28181-sip/src/main/java/cn/skcks/docking/gb28181/sip/method/register/RegisterBuilder.java b/gb28181-sip/src/main/java/cn/skcks/docking/gb28181/sip/method/register/RegisterBuilder.java new file mode 100644 index 0000000..31f710a --- /dev/null +++ b/gb28181-sip/src/main/java/cn/skcks/docking/gb28181/sip/method/register/RegisterBuilder.java @@ -0,0 +1,20 @@ +package cn.skcks.docking.gb28181.sip.method.register; + +import lombok.*; +import lombok.experimental.SuperBuilder; + +import javax.sip.message.Request; + +@SuperBuilder +@Data +public class RegisterBuilder { + @Getter + private static final String method = Request.REGISTER; + private String localIp; + private int localPort; + private String localId; + private String targetIp; + private int targetPort; + private String targetId; + private String transport; +} diff --git a/gb28181-sip/src/main/java/cn/skcks/docking/gb28181/sip/method/register/request/RegisterRequestBuilder.java b/gb28181-sip/src/main/java/cn/skcks/docking/gb28181/sip/method/register/request/RegisterRequestBuilder.java new file mode 100644 index 0000000..5a7e2a1 --- /dev/null +++ b/gb28181-sip/src/main/java/cn/skcks/docking/gb28181/sip/method/register/request/RegisterRequestBuilder.java @@ -0,0 +1,53 @@ +package cn.skcks.docking.gb28181.sip.method.register.request; + +import cn.skcks.docking.gb28181.sip.generic.SipBuilder; +import cn.skcks.docking.gb28181.sip.generic.SipRequestBuilder; +import cn.skcks.docking.gb28181.sip.method.register.RegisterBuilder; +import cn.skcks.docking.gb28181.sip.utils.DigestAuthenticationHelper; +import cn.skcks.docking.gb28181.sip.utils.SipUtil; +import gov.nist.javax.sip.message.SIPRequest; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.SneakyThrows; +import lombok.ToString; +import lombok.experimental.SuperBuilder; +import lombok.extern.slf4j.Slf4j; + +import javax.sip.address.Address; +import javax.sip.address.SipURI; +import javax.sip.header.AuthorizationHeader; +import javax.sip.header.WWWAuthenticateHeader; +import javax.sip.message.Request; + +@Slf4j +@Data +@SuperBuilder +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +public class RegisterRequestBuilder extends RegisterBuilder { + public Request createNoAuthorizationRequest(String callId, int expires) { + String local = SipBuilder.createHostAddress(getLocalIp(), getLocalPort()); + Address localAddress = SipBuilder.createAddress(SipBuilder.createSipURI(getLocalId(), local)); + String target = SipBuilder.createHostAddress(getTargetIp(), getTargetPort()); + SipURI targetUri = SipBuilder.createSipURI(getTargetId(), target); + + Request request = SipRequestBuilder.createRequest(targetUri, getMethod(), + SipBuilder.createCallIdHeader(callId), + SipBuilder.createCSeqHeader(1L, getMethod()), + SipBuilder.createFromHeader(localAddress, SipUtil.generateFromTag()), + SipBuilder.createToHeader(localAddress), + SipBuilder.createViaHeaders(getTargetIp(), getTargetPort(), getTransport(), SipUtil.generateViaTag()), + SipBuilder.createMaxForwardsHeader(70)); + return SipBuilder.addHeaders(request, + SipBuilder.createExpiresHeader(expires), + SipBuilder.createContactHeader(localAddress)); + } + + @SneakyThrows + public Request createAuthorizationRequest(String callId, int expires, String id, String passwd, WWWAuthenticateHeader wwwAuthenticateHeader) { + SIPRequest request = (SIPRequest) createNoAuthorizationRequest(callId, expires); + request.getCSeq().setSeqNumber(2L); + AuthorizationHeader authorization = DigestAuthenticationHelper.createAuthorization(getMethod(), getTargetIp(), getTargetPort(), getTargetId(), id, passwd, wwwAuthenticateHeader); + return SipBuilder.addHeaders(request,authorization); + } +} diff --git a/gb28181-sip/src/main/java/cn/skcks/docking/gb28181/sip/method/register/response/RegisterResponseBuilder.java b/gb28181-sip/src/main/java/cn/skcks/docking/gb28181/sip/method/register/response/RegisterResponseBuilder.java new file mode 100644 index 0000000..c8aada4 --- /dev/null +++ b/gb28181-sip/src/main/java/cn/skcks/docking/gb28181/sip/method/register/response/RegisterResponseBuilder.java @@ -0,0 +1,65 @@ +package cn.skcks.docking.gb28181.sip.method.register.response; + +import cn.skcks.docking.gb28181.sip.generic.SipBuilder; +import cn.skcks.docking.gb28181.sip.generic.SipResponseBuilder; +import cn.skcks.docking.gb28181.sip.method.register.RegisterBuilder; +import cn.skcks.docking.gb28181.sip.utils.DigestAuthenticationHelper; +import cn.skcks.docking.gb28181.sip.utils.SipUtil; +import gov.nist.javax.sip.header.Authorization; +import gov.nist.javax.sip.message.SIPRequest; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.ToString; +import lombok.experimental.SuperBuilder; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.StringUtils; + +import javax.sip.header.WWWAuthenticateHeader; +import javax.sip.message.Request; +import javax.sip.message.Response; + +@Slf4j +@Data +@SuperBuilder +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +public class RegisterResponseBuilder extends RegisterBuilder { + /** + * 不做任何校验 即无密码时 使用的认证响应 (如果请求的method错误 依然返回 401 认证失败) + * @param request 请求 + */ + public Response createPassedAuthorzatioinResponse(Request request){ + SIPRequest sipRequest = (SIPRequest) request; + if(!StringUtils.equalsIgnoreCase(sipRequest.getMethod(), getMethod())){ + return SipBuilder.addHeaders( + SipResponseBuilder.createResponse(Response.UNAUTHORIZED, request), + sipRequest.getContactHeader()); + } + return SipBuilder.addHeaders( + SipResponseBuilder.createResponse(Response.OK, request), + sipRequest.getContactHeader(), + sipRequest.getExpires()); + } + + public Response createAuthorzatioinResponse(Request request, String password){ + SIPRequest sipRequest = (SIPRequest) request; + Authorization authorization = sipRequest.getAuthorization(); + if(authorization == null){ + String realm = SipUtil.nanoId(); + WWWAuthenticateHeader wwwAuthenticateHeader = DigestAuthenticationHelper.generateChallenge(realm); + return SipBuilder.addHeaders( + SipResponseBuilder.createResponse(Response.UNAUTHORIZED, request), + sipRequest.getContactHeader(), + wwwAuthenticateHeader); + } + boolean passed = DigestAuthenticationHelper.doAuthenticatePlainTextPassword(request,password); + if(!passed){ + sipRequest.removeHeader(Authorization.NAME); + return createAuthorzatioinResponse(request, password); + } + return SipBuilder.addHeaders( + SipResponseBuilder.createResponse(Response.OK, request), + sipRequest.getContactHeader(), + sipRequest.getExpires()); + } +} diff --git a/gb28181-sip/src/main/java/cn/skcks/docking/gb28181/sip/request/RegisterRequestBuilder.java b/gb28181-sip/src/main/java/cn/skcks/docking/gb28181/sip/request/RegisterRequestBuilder.java deleted file mode 100644 index 02d9ed9..0000000 --- a/gb28181-sip/src/main/java/cn/skcks/docking/gb28181/sip/request/RegisterRequestBuilder.java +++ /dev/null @@ -1,52 +0,0 @@ -package cn.skcks.docking.gb28181.sip.request; - -import cn.skcks.docking.gb28181.sip.generic.SipBuilder; -import cn.skcks.docking.gb28181.sip.generic.SipRequestBuilder; -import cn.skcks.docking.gb28181.sip.utils.DigestAuthenticationHelper; -import cn.skcks.docking.gb28181.sip.utils.SipUtil; -import lombok.AllArgsConstructor; -import lombok.extern.slf4j.Slf4j; - -import javax.sip.address.Address; -import javax.sip.address.SipURI; -import javax.sip.header.AuthorizationHeader; -import javax.sip.header.WWWAuthenticateHeader; -import javax.sip.message.Request; - -@AllArgsConstructor -@Slf4j -public class RegisterRequestBuilder { - private static final String method = Request.REGISTER; - private String localIp; - private int localPort; - private String localId; - private String targetIp; - private int targetPort; - private String targetId; - - private String transport; - - public Request createNoAuthorizationRequest(String callId, int expires) { - String local = SipBuilder.createHostAddress(localIp, localPort); - Address localAddress = SipBuilder.createAddress(SipBuilder.createSipURI(localId, local)); - String target = SipBuilder.createHostAddress(targetIp, targetPort); - SipURI targetUri = SipBuilder.createSipURI(targetId, target); - - Request request = SipRequestBuilder.createRequest(targetUri, method, - SipBuilder.createCallIdHeader(callId), - SipBuilder.createCSeqHeader(1L, method), - SipBuilder.createFromHeader(localAddress, SipUtil.generateFromTag()), - SipBuilder.createToHeader(localAddress), - SipBuilder.createViaHeaders(targetIp, targetPort, transport, SipUtil.generateViaTag()), - SipBuilder.createMaxForwardsHeader(70)); - request.addHeader(SipBuilder.createExpiresHeader(expires)); - return request; - } - - public Request createNoAuthorizationRequest(String callId, int expires, String id, String passwd, WWWAuthenticateHeader wwwAuthenticateHeader) { - Request request = createNoAuthorizationRequest(callId, expires); - AuthorizationHeader authorization = DigestAuthenticationHelper.createAuthorization(method, targetIp, targetPort, targetId, id, passwd, wwwAuthenticateHeader); - request.addHeader(authorization); - return request; - } -} diff --git a/gb28181-sip/src/test/java/cn/skcks/docking/gb28181/sip/SipTest.java b/gb28181-sip/src/test/java/cn/skcks/docking/gb28181/sip/SipTest.java index 0edb4a8..0800f5b 100644 --- a/gb28181-sip/src/test/java/cn/skcks/docking/gb28181/sip/SipTest.java +++ b/gb28181-sip/src/test/java/cn/skcks/docking/gb28181/sip/SipTest.java @@ -6,10 +6,16 @@ import cn.skcks.docking.gb28181.sip.header.XGBVerHeader; import cn.skcks.docking.gb28181.sip.header.impl.XGBVerHeaderImpl; import cn.skcks.docking.gb28181.sip.generic.SipRequestBuilder; import cn.skcks.docking.gb28181.sip.generic.SipResponseBuilder; +import cn.skcks.docking.gb28181.sip.parser.GbStringMsgParserFactory; +import cn.skcks.docking.gb28181.sip.property.DefaultProperties; import cn.skcks.docking.gb28181.sip.utils.SipUtil; +import gov.nist.javax.sip.SipStackImpl; +import lombok.SneakyThrows; import lombok.extern.slf4j.Slf4j; import org.junit.jupiter.api.Test; +import javax.sip.ListeningPoint; +import javax.sip.SipProvider; import javax.sip.address.Address; import javax.sip.address.SipURI; import javax.sip.header.*; @@ -20,6 +26,24 @@ import java.util.List; @Slf4j public class SipTest { + @Test + @SneakyThrows + public void stackTest(){ + // 创建 sip + SipStackImpl sipStack = (SipStackImpl) SipBuilder.getSipFactory() + .createSipStack(DefaultProperties.getProperties( + SipUtil.UserAgent, + "cn.skcks.docking.gb28181.sip.logger.StackLoggerImpl", + "cn.skcks.docking.gb28181.sip.logger.ServerLoggerImpl")); + sipStack.setMessageParserFactory(new GbStringMsgParserFactory()); + ListeningPoint listeningPoint = sipStack.createListeningPoint("127.0.0.1", 5060, ListeningPoint.UDP); + SipProvider sipProvider = sipStack.createSipProvider(listeningPoint); + // 各种操作... + Thread.sleep(1000); + // 关闭 sip + sipStack.deleteSipProvider(sipProvider); + sipStack.deleteListeningPoint(listeningPoint); + } @Test public void test() { SipUtil.setUserAgent("GB28181-Docking-Platform Beta"); diff --git a/gb28181-sip/src/test/java/cn/skcks/docking/gb28181/sip/process/RequestTest.java b/gb28181-sip/src/test/java/cn/skcks/docking/gb28181/sip/process/RequestTest.java index e4acf8b..696c8bd 100644 --- a/gb28181-sip/src/test/java/cn/skcks/docking/gb28181/sip/process/RequestTest.java +++ b/gb28181-sip/src/test/java/cn/skcks/docking/gb28181/sip/process/RequestTest.java @@ -1,19 +1,17 @@ package cn.skcks.docking.gb28181.sip.process; -import cn.skcks.docking.gb28181.sip.generic.SipBuilder; -import cn.skcks.docking.gb28181.sip.parser.GbStringMsgParserFactory; -import cn.skcks.docking.gb28181.sip.property.DefaultProperties; -import cn.skcks.docking.gb28181.sip.request.RegisterRequestBuilder; -import cn.skcks.docking.gb28181.sip.utils.SipUtil; -import gov.nist.javax.sip.SipStackImpl; +import cn.hutool.core.util.IdUtil; +import cn.skcks.docking.gb28181.sip.method.register.request.RegisterRequestBuilder; +import cn.skcks.docking.gb28181.sip.method.register.response.RegisterResponseBuilder; +import gov.nist.javax.sip.message.SIPResponse; import lombok.SneakyThrows; import lombok.extern.slf4j.Slf4j; import org.junit.jupiter.api.Test; import javax.sip.ListeningPoint; -import javax.sip.SipProvider; -import javax.sip.header.UserAgentHeader; +import javax.sip.header.WWWAuthenticateHeader; import javax.sip.message.Request; +import javax.sip.message.Response; @Slf4j public class RequestTest { @@ -27,25 +25,47 @@ public class RequestTest { @Test @SneakyThrows - void test(){ - SipUtil.setUserAgentVersion("0.1.0"); - UserAgentHeader userAgentHeader = SipBuilder.userAgentHeader; - log.info("\n{}",userAgentHeader); + void test() { + String callId = IdUtil.fastSimpleUUID(); + RegisterRequestBuilder registerRequestBuilder = RegisterRequestBuilder.builder() + .localIp(localIp) + .localPort(localPort) + .localId(localId) + .targetIp(remoteIp) + .targetPort(remotePort) + .targetId(remoteId) + .transport(ListeningPoint.UDP) + .build(); - SipStackImpl sipStack = (SipStackImpl) SipBuilder.getSipFactory() - .createSipStack(DefaultProperties.getProperties( - SipUtil.UserAgent, - "cn.skcks.docking.gb28181.sip.logger.StackLoggerImpl", - "cn.skcks.docking.gb28181.sip.logger.ServerLoggerImpl")); - sipStack.setMessageParserFactory(new GbStringMsgParserFactory()); - ListeningPoint listeningPoint = sipStack.createListeningPoint("127.0.0.1", 5060, ListeningPoint.UDP); - SipProvider sipProvider = sipStack.createSipProvider(listeningPoint); - String callId = sipProvider.getNewCallId().getCallId(); + RegisterResponseBuilder registerResponseBuilder = RegisterResponseBuilder.builder() + .localIp(remoteIp) + .localPort(remotePort) + .localId(remoteId) + .targetIp(localIp) + .targetPort(localPort) + .targetId(localId) + .transport(ListeningPoint.UDP) + .build(); - RegisterRequestBuilder registerRequestBuilder = new RegisterRequestBuilder(localIp, localPort, localId, remoteIp, remotePort, remoteId, ListeningPoint.UDP); + log.info("无密码的认证"); Request noAuthorizationRequest = registerRequestBuilder.createNoAuthorizationRequest(callId, 3600); - log.info("\n{}",noAuthorizationRequest); - sipStack.deleteSipProvider(sipProvider); - sipStack.deleteListeningPoint(listeningPoint); + log.info("\n{}", noAuthorizationRequest); + // 服务端不设置无密码直接通过 + Response passedAuthorzatioinResponse = registerResponseBuilder.createPassedAuthorzatioinResponse(noAuthorizationRequest); + log.info("\n{}", passedAuthorzatioinResponse); + + log.info("有密码的认证"); + Response authorzatioinResponse = registerResponseBuilder.createAuthorzatioinResponse(noAuthorizationRequest, "123456"); + log.info("\n{}", noAuthorizationRequest); + // 401 响应 + log.info("\n{}", authorzatioinResponse); + SIPResponse sipResponse = (SIPResponse)authorzatioinResponse; + WWWAuthenticateHeader wwwAuthenticateHeader = (WWWAuthenticateHeader)sipResponse.getHeader(WWWAuthenticateHeader.NAME); + // 重新发起带有认证信息的请求 + Request authorizationRequest = registerRequestBuilder.createAuthorizationRequest(callId, 3600, localId, "123456", wwwAuthenticateHeader); + log.info("\n{}", authorizationRequest); + authorzatioinResponse = registerResponseBuilder.createAuthorzatioinResponse(authorizationRequest, "123456"); + // 注册成功 + log.info("\n{}", authorzatioinResponse); } }