├── .gitignore ├── CHANGELOG ├── Jenkinsfile ├── README.md ├── conf └── ocp │ └── VHosts.xml ├── kb-s2i ├── build.sh └── deploy.sh ├── pom.xml ├── wowza-chaos-vhost ├── pom.xml └── src │ └── main │ ├── assembly │ └── assembly.xml │ └── config │ ├── wowza_vhost_chaos_chaosv6 │ └── conf │ │ ├── MediaCache.xml │ │ ├── StartupStreams.xml │ │ ├── Tune.xml │ │ ├── VHost.xml │ │ ├── admin.password │ │ ├── chaos │ │ ├── Application.xml │ │ └── wowza-modules.properties │ │ ├── chaosnonapple │ │ ├── Application.xml │ │ └── wowza-modules.properties │ │ ├── clientaccesspolicy.xml │ │ ├── crossdomain.xml │ │ └── log4j.properties │ ├── wowza_vhost_chaos_chaosv6_doms │ └── conf │ │ ├── MediaCache.xml │ │ ├── StartupStreams.xml │ │ ├── Tune.xml │ │ ├── VHost.xml │ │ ├── admin.password │ │ ├── chaos │ │ ├── Application.xml │ │ └── wowza-modules.properties │ │ ├── chaosnonapple │ │ ├── Application.xml │ │ └── wowza-modules.properties │ │ ├── clientaccesspolicy.xml │ │ ├── crossdomain.xml │ │ └── log4j.properties │ ├── wowza_vhost_chaos_chaosv6_doms_stageapi │ └── conf │ │ ├── MediaCache.xml │ │ ├── StartupStreams.xml │ │ ├── Tune.xml │ │ ├── VHost.xml │ │ ├── admin.password │ │ ├── chaos │ │ ├── Application.xml │ │ └── wowza-modules.properties │ │ ├── chaosnonapple │ │ ├── Application.xml │ │ └── wowza-modules.properties │ │ ├── clientaccesspolicy.xml │ │ ├── crossdomain.xml │ │ └── log4j.properties │ └── wowza_vhost_chaos_chaosv6_stageapi │ └── conf │ ├── MediaCache.xml │ ├── StartupStreams.xml │ ├── Tune.xml │ ├── VHost.xml │ ├── admin.password │ ├── chaos │ ├── Application.xml │ └── wowza-modules.properties │ ├── chaosnonapple │ ├── Application.xml │ └── wowza-modules.properties │ ├── clientaccesspolicy.xml │ ├── crossdomain.xml │ └── log4j.properties ├── wowza-chaosv6-authorization-module ├── pom.xml └── src │ ├── main │ └── java │ │ └── dk │ │ └── statsbiblioteket │ │ └── medieplatform │ │ └── wowza │ │ └── plugin │ │ └── authentication │ │ ├── ChaosV6API.java │ │ ├── ChaosV6SessionAndFilenameValidater.java │ │ └── WowzaSessionAuthenticationChaosV6ModuleBase.java │ └── test │ ├── java │ └── dk │ │ └── statsbiblioteket │ │ └── medieplatform │ │ └── wowza │ │ └── plugin │ │ └── authentication │ │ └── model │ │ └── ChaosV6SessionAndFilenameValidaterTest.java │ └── resources │ ├── test_data_chaosv6_output_full.xml │ ├── test_data_chaosv6_output_invalid_session.xml │ └── test_data_invalid_output.xml ├── wowza-common ├── pom.xml └── src │ ├── main │ └── java │ │ └── dk │ │ └── statsbiblioteket │ │ └── medieplatform │ │ └── wowza │ │ └── plugin │ │ ├── ticket │ │ └── TicketToolInterface.java │ │ └── utilities │ │ ├── ConfigReader.java │ │ ├── IllegallyFormattedQueryStringException.java │ │ └── StringAndTextUtil.java │ └── test │ └── java │ └── dk │ └── statsbiblioteket │ └── medieplatform │ └── wowza │ └── plugin │ └── utilities │ └── StringAndTextUtilTest.java ├── wowza-content-resolver-module ├── pom.xml └── src │ ├── main │ └── java │ │ └── dk │ │ └── statsbiblioteket │ │ └── medieplatform │ │ └── wowza │ │ └── plugin │ │ ├── ContentResolverMapper.java │ │ └── ContentResolverModule.java │ └── test │ ├── java │ └── dk │ │ └── statsbiblioteket │ │ └── medieplatform │ │ └── wowza │ │ └── plugin │ │ └── ContentResolverMapperTest.java │ └── resources │ └── streamingDir │ ├── 0 │ └── e │ │ └── f │ │ └── 8 │ │ └── 0ef8f946-4e90-4c9d-843a-a03504d2ee6c.flv │ └── README.streamingDir ├── wowza-db-statistics-module ├── pom.xml └── src │ ├── main │ └── java │ │ └── dk │ │ └── statsbiblioteket │ │ └── medieplatform │ │ └── wowza │ │ └── plugin │ │ └── statistic │ │ ├── StatisticLoggingSBModuleBase.java │ │ └── logger │ │ └── db │ │ └── StreamingDatabaseEventLogger.java │ └── test │ └── java │ └── dk │ └── statsbiblioteket │ └── medieplatform │ └── wowza │ └── plugin │ ├── mockobjects │ └── MCMPortalInterfaceStatisticsMock.java │ └── statistic │ ├── StatisticLoggingStreamListenerTest.java │ └── logger │ └── db │ └── StreamingDatabaseEventLoggerTest.java ├── wowza-mcm-authorization-module ├── pom.xml └── src │ ├── main │ └── java │ │ └── dk │ │ └── statsbiblioteket │ │ └── medieplatform │ │ └── wowza │ │ └── plugin │ │ └── authentication │ │ ├── StreamAuthenticater.java │ │ ├── WowzaSessionAuthenticationModuleBase.java │ │ └── model │ │ ├── MCMOReturnValueWrapper.java │ │ ├── MCMOutputException.java │ │ ├── MCMSessionAndFilenameValidater.java │ │ └── SessionAndFilenameValidaterIF.java │ └── test │ ├── java │ └── dk │ │ └── statsbiblioteket │ │ └── medieplatform │ │ └── wowza │ │ └── plugin │ │ ├── authentication │ │ ├── StreamAuthenticaterTest.java │ │ └── model │ │ │ ├── MCMOReturnValueWrapperTest.java │ │ │ └── MCMSessionAndFilenameValidaterTest.java │ │ └── mockobjects │ │ └── SessionAndFilenameValidaterMock.java │ └── resources │ ├── test_data_MCM_output_full.xml │ ├── test_data_MCM_output_invalid_session.xml │ ├── test_data_MCM_output_multiple_files.xml │ └── test_data_invalid_output.xml ├── wowza-mcm-statistics-module ├── pom.xml └── src │ └── main │ └── java │ └── dk │ └── statsbiblioteket │ └── medieplatform │ └── wowza │ └── plugin │ └── statistic │ ├── StatisticLoggingMCMModuleBase.java │ ├── StatisticLoggingStreamListener.java │ └── logger │ ├── SessionIDPair.java │ ├── StreamingEventLoggerIF.java │ ├── StreamingStatLogEntry.java │ └── mcm │ ├── MCMPortalInterfaceStatistics.java │ ├── MCMPortalInterfaceStatisticsImpl.java │ └── StreamingMCMEventLogger.java ├── wowza-mcm3-authorization-module ├── pom.xml └── src │ ├── main │ └── java │ │ └── dk │ │ └── statsbiblioteket │ │ └── medieplatform │ │ └── wowza │ │ └── plugin │ │ └── authentication │ │ ├── MCM3OReturnValueWrapper.java │ │ ├── MCM3SessionAndFilenameValidater.java │ │ └── WowzaSessionAuthenticationMCM3ModuleBase.java │ └── test │ ├── java │ └── dk │ │ └── statsbiblioteket │ │ └── medieplatform │ │ └── wowza │ │ └── plugin │ │ └── authentication │ │ └── model │ │ ├── MCM3OReturnValueWrapperTest.java │ │ └── MCM3SessionAndFilenameValidaterTest.java │ └── resources │ ├── test_data_MCM3_output_full.xml │ ├── test_data_MCM3_output_invalid_session.xml │ └── test_data_invalid_output.xml ├── wowza-mediestream-vhost ├── pom.xml └── src │ └── main │ ├── assembly │ └── assembly.xml │ ├── config │ └── wowza_vhost_mediestream │ │ └── conf │ │ ├── MediaCache.xml │ │ ├── StartupStreams.xml │ │ ├── Tune.xml │ │ ├── VHost.xml │ │ ├── admin.password │ │ ├── clientaccesspolicy.xml │ │ ├── crossdomain.xml │ │ ├── log4j.properties │ │ ├── mediestream │ │ ├── Application.xml │ │ └── wowza-modules.properties │ │ ├── mediestream_preview │ │ └── Application.xml │ │ └── mediestreamapple │ │ ├── Application.xml │ │ └── wowza-modules.properties │ └── scripts │ ├── testmediestream.sh │ ├── watchmisuse.py │ └── watchplayer.py ├── wowza-statistics-module ├── pom.xml └── src │ ├── main │ └── java │ │ └── dk │ │ └── statsbiblioteket │ │ └── medieplatform │ │ └── wowza │ │ └── plugin │ │ ├── StreamingStatisticsIMediaStreamActionNotify2.java │ │ ├── StreamingStatisticsModule.java │ │ └── streamingstatistics │ │ ├── StreamingEventLogger.java │ │ └── StreamingStatLogEntry.java │ └── test │ └── java │ └── dk │ └── statsbiblioteket │ └── medieplatform │ └── wowza │ └── plugin │ └── streamingstatistics │ ├── StreamingEventLoggerTest.java │ └── StreamingStatLogEntryTest.java └── wowza-ticket-checker-module ├── pom.xml └── src ├── main └── java │ └── dk │ └── statsbiblioteket │ └── medieplatform │ └── wowza │ └── plugin │ ├── StreamAuthenticator.java │ ├── TicketChecker.java │ ├── TicketCheckerModule.java │ └── ticket │ └── TicketTool.java └── test └── java └── dk └── statsbiblioteket └── medieplatform └── wowza └── plugin ├── TicketCheckerTest.java └── ticket └── TicketToolTest.java /.gitignore: -------------------------------------------------------------------------------- 1 | target/ 2 | .idea/ 3 | *.ipr 4 | *.iml 5 | *.iws 6 | .settings/ 7 | .project 8 | .classpath 9 | 10 | -------------------------------------------------------------------------------- /Jenkinsfile: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env groovy 2 | 3 | 4 | openshift.withCluster() { // Use "default" cluster or fallback to OpenShift cluster detection 5 | 6 | 7 | echo "Hello from the project running Jenkins: ${openshift.project()}" 8 | 9 | //Create template with maven settings.xml, so we have credentials for nexus 10 | podTemplate( 11 | inheritFrom: 'kb-jenkins-agent-wowza', 12 | cloud: 'openshift', //cloud must be openshift 13 | volumes: [ //mount the settings.xml 14 | secretVolume(mountPath: '/etc/m2', secretName: 'maven-settings') 15 | ]) { 16 | 17 | //Stages outside a node declaration runs on the jenkins host 18 | 19 | String projectName = encodeName("${JOB_NAME}") 20 | echo "name=${projectName}" 21 | 22 | try { 23 | //GO to a node with maven and settings.xml 24 | node(POD_LABEL) { 25 | //Do not use concurrent builds 26 | properties([disableConcurrentBuilds()]) 27 | 28 | def mvnCmd = "mvn -s /etc/m2/settings.xml --batch-mode" 29 | 30 | stage('checkout') { 31 | checkout scm 32 | } 33 | 34 | stage('Mvn clean verify') { 35 | sh "${mvnCmd} -PallTests clean verify" 36 | } 37 | 38 | stage('Analyze build results') { 39 | recordIssues aggregatingResults: true, 40 | tools: [java(), 41 | javaDoc(), 42 | mavenConsole(), 43 | taskScanner(highTags:'FIXME', normalTags:'TODO', includePattern: '**/*.java', excludePattern: 'target/**/*')] 44 | } 45 | 46 | stage('Create test project') { 47 | recreateProject(projectName) 48 | 49 | openshift.withProject(projectName) { 50 | 51 | stage("Create build and deploy application") { 52 | openshift.newBuild("--strategy source", "--binary", "-i kb-infra/kb-s2i-wowza", "--name wowza") 53 | openshift.startBuild("wowza", "--from-dir=.", "--follow") 54 | openshift.newApp("wowza", "-e BUILD_NUMBER=latest") 55 | openshift.create("route", "edge", "--service=wowza") 56 | } 57 | } 58 | } 59 | 60 | stage('Push to Nexus (if Master)') { 61 | sh 'env' 62 | echo "Branch name ${env.BRANCH_NAME}" 63 | if (env.BRANCH_NAME == 'master') { 64 | sh "${mvnCmd} clean deploy -DskipTests=true" 65 | } else { 66 | echo "Branch ${env.BRANCH_NAME} is not master, so no mvn deploy" 67 | } 68 | } 69 | 70 | stage('Promote image') { 71 | if (env.BRANCH_NAME == 'master') { 72 | configFileProvider([configFile(fileId: "imagePromoter", variable: 'promoter')]) { 73 | def promoter = load promoter 74 | promoter.promoteImage("wowza", "${projectName}", "medieplatform", "latest") 75 | } 76 | } else { 77 | echo "Branch ${env.BRANCH_NAME} is not master, so no mvn deploy" 78 | } 79 | } 80 | 81 | stage('Cleanup') { 82 | echo "Cleaning up" 83 | openshift.selector("project/${projectName}").delete() 84 | } 85 | } 86 | } catch (e) { 87 | currentBuild.result = 'FAILURE' 88 | throw e 89 | } 90 | } 91 | } 92 | 93 | 94 | private void recreateProject(String projectName) { 95 | echo "Delete the project ${projectName}, ignore errors if the project does not exist" 96 | try { 97 | openshift.selector("project/${projectName}").delete() 98 | 99 | openshift.selector("project/${projectName}").watch { 100 | echo "Waiting for the project ${projectName} to be deleted" 101 | return it.count() == 0 102 | } 103 | 104 | } catch (e) { 105 | 106 | } 107 | // 108 | // //Wait for the project to be gone 109 | // sh "until ! oc get project ${projectName}; do date;sleep 2; done; exit 0" 110 | 111 | echo "Create the project ${projectName}" 112 | openshift.newProject(projectName) 113 | } 114 | 115 | /** 116 | * Encode the jobname as a valid openshift project name 117 | * @param jobName the name of the job 118 | * @return the jobname as a valid openshift project name 119 | */ 120 | private static String encodeName(groovy.lang.GString jobName) { 121 | def jobTokens = jobName.tokenize("/") 122 | def repo = jobTokens[0] 123 | if(repo.contains('-')) { 124 | repo = repo.tokenize("-").collect{it.take(1)}.join("") 125 | } else { 126 | repo = repo.take(3) 127 | } 128 | 129 | def name = ([repo] + jobTokens.drop(1)).join("-") 130 | .replaceAll("\\s", "-") 131 | .replaceAll("_", "-") 132 | .replace("/", '-') 133 | .replaceAll("^openshift-", "") 134 | .toLowerCase() 135 | return name 136 | } 137 | 138 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # wowza-modules 2 | These are modules for Wowza 4.8.5 used at the Royal Danish Library. 3 | 4 | It consists of 8 modules and three example VHosts 5 | 6 | ## The modules 7 | wowza-content-resolver-module 8 | Given configuration, lookup streams in diferent directory structure 9 | 10 | wowza-ticket-checker-module 11 | Read a ticket ID from query param, and check that it is a ticket issued for the given stream and ip of client 12 | 13 | wowza-statistics-module 14 | Log events from wowza to a simple text file. Also logs information from ticket. 15 | 16 | wowza-mcm-authorization-module 17 | Given a query parameter, check that it as a valid MCM session. This module is deprecated. Use MCM3 module instead. 18 | Some classes are used by wowza-mcm3-authorization-module 19 | 20 | wowza-mcm3-authorization-module 21 | Given a query parameter, check that it as a valid MCM3 session 22 | 23 | wowza-chaosv6-authorization-module 24 | Given a query parameter, check that it as a valid chaosv6 session 25 | 26 | wowza-mcm-statistics-module 27 | Log events from wowza to MCM. This module is deprecated, statistics logging is not supported in MCM3. Some classes 28 | are used by wowza-db-statistics-module. 29 | 30 | wowza-db-statistics-module 31 | Log events from wowza to a database, including MCM session information. 32 | 33 | 34 | ## The VHosts 35 | ### wowza-mediestream-vhost 36 | 37 | A complete VHost that contains configuration and the modules 38 | * wowza-content-resolver-module 39 | * wowza-ticket-checker-module 40 | * wowza-statistics-module 41 | Example configuration can be found in conf/mediestream/wowza-modules.properties 42 | The streamingContent directory in the VHost should point to the content to be served. 43 | conf/Vhost.xml should probably be updated with correct port numbers 44 | 45 | ### wowza-chaos-vhost 46 | 47 | Four complete VHosts that contain configuration and the modules 48 | * wowza-content-resolver-module (only in two VHosts) 49 | * wowza-chaosv6-authorization-module 50 | * wowza-db-statistics-module 51 | Example configuration can be found in conf/chaos/wowza-modules.properties 52 | The streamingContent directory in the VHost should point to the content to be served. 53 | conf/Vhost.xml should probably be updated with correct port numbers 54 | 55 | ## Requirements 56 | The project requires Java 11 to be built and run. Known to build with OpenJDK 11, other JDKs may work 57 | 58 | The project depends on java libraies from WowzaStreamingEngine, and as a commercial product can't be included. To obtain the needed libraies an installation of WowzaStreamingEngine is required. 59 | WowzaStreamingEngine installation program and developer license can be obtained from [Wowza](http://www.wowza.com/streaming/developers). 60 | The installer itself offers arguments to specify non-standard installation directory but does not respect the value, and additionally requires super-user rights to install itself in the default location of `/usr/local/WowzaStreamingEngine-${wms.version}`. 61 | Part of the maven project lifecycle (`verify` phase) the needed libraries will be installed from `/usr/local/WowzaStreamingEngine-${wms.version}/lib` into the local maven repository/cache. 62 | 63 | ## Building 64 | Use maven to build the project i.e. `mvn clean package` 65 | 66 | ## Test 67 | There are unit tests that are run during the default build (see above). 68 | 69 | Operative tests of the product requires an installation, available streaming content and additional infrastructure (content-resolver, ticket system). Internally at The Royal Danish Library we have a setup for that currently running on the server `iapetus`. 70 | -------------------------------------------------------------------------------- /conf/ocp/VHosts.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | _mediestreamVHost_ 6 | /app/conf/wowza-mediestream-vhost 7 | 0 8 | 9 | 29 | 30 | 31 | 32 | -------------------------------------------------------------------------------- /kb-s2i/build.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | cd /tmp/src 4 | 5 | tar xf /tmp/src/wowza-mediestream-vhost/target/wowza-mediestream-vhost-*-bundle.tar.gz -C /app/conf/ 6 | mv /app/conf/wowza-mediestream-vhost-* /app/conf/wowza-mediestream-vhost 7 | 8 | -------------------------------------------------------------------------------- /kb-s2i/deploy.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | cp -- /tmp/src/conf/ocp/VHosts.xml "$CONF_DIR/VHosts.xml" 4 | 5 | sed -i 's|${user.home}/services/keystore.jks|/app/conf/keystore.jks|' /app/conf/wowza-mediestream-vhost/conf/VHost.xml 6 | 7 | cp /app/conf/wowza-mediestream-vhost/conf/mediestream/wowza-modules.properties /app/conf/mediestream-wowza-modules.properties 8 | ln -sf /app/conf/mediestream-wowza-modules.properties /app/conf/wowza-mediestream-vhost/conf/mediestream/wowza-modules.properties 9 | ln -sf /app/conf/mediestream-wowza-modules.properties /app/conf/wowza-mediestream-vhost/conf/mediestreamapple/wowza-modules.properties 10 | chmod -R g+w /app/conf 11 | 12 | mkdir -p /app/content/mediestream/{doms,kuana,kuanaradio} 13 | ln -s /app/content/mediestream/doms /app/conf/wowza-mediestream-vhost/streamingContent/doms 14 | ln -s /app/content/mediestream/kuana /app/conf/wowza-mediestream-vhost/streamingContent/kuana 15 | ln -s /app/content/mediestream/kuanaradio /app/conf/wowza-mediestream-vhost/streamingContent/kuanaradio 16 | -------------------------------------------------------------------------------- /wowza-chaos-vhost/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4.0.0 4 | 5 | 6 | dk.statsbiblioteket.medieplatform 7 | wowza-modules 8 | 4.8-SNAPSHOT 9 | 10 | 11 | wowza-chaos-vhost 12 | pom 13 | 14 | 15 | 16 | 17 | maven-assembly-plugin 18 | 2.2.2 19 | 20 | 21 | make-assembly 22 | 23 | 24 | src/main/assembly/assembly.xml 25 | 26 | gnu 27 | 28 | 29 | package 30 | 31 | 32 | single 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | org.postgresql 44 | postgresql 45 | runtime 46 | 47 | 48 | 49 | dk.statsbiblioteket.medieplatform 50 | wowza-db-statistics-module 51 | 52 | 53 | 54 | dk.statsbiblioteket.medieplatform 55 | wowza-mcm3-authorization-module 56 | 57 | 58 | 59 | dk.statsbiblioteket.medieplatform 60 | wowza-chaosv6-authorization-module 61 | 62 | 63 | 64 | dk.statsbiblioteket.medieplatform 65 | wowza-content-resolver-module 66 | 67 | 68 | 69 | -------------------------------------------------------------------------------- /wowza-chaos-vhost/src/main/config/wowza_vhost_chaos_chaosv6/conf/MediaCache.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | ${com.wowza.wms.TuningAuto} 7 | 8 | 9 | ${com.wowza.wms.TuningAuto} 10 | 11 | ${com.wowza.wms.TuningAuto} 12 | ${com.wowza.wms.TuningAuto} 13 | 10000 14 | 15 | true 16 | true 17 | false 18 | false 19 | true 20 | false 21 | 22 | 23 | 24 | 25 | default 26 | Default Store 27 | 28 | ${com.wowza.wms.context.ServerConfigHome}/mediacache 29 | 10G 30 | 24 31 | 24 32 | 1000 33 | 16M 34 | 64M 35 | 100 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | dvrorigin 46 | HTTP 47 | Default DVR source 48 | http:// 49 | dvrorigin/ 50 | com.wowza.wms.mediacache.impl.MediaCacheItemHTTPImpl 51 | 52 | 262144 53 | 1200000 54 | 600000 55 | true 56 | 50 57 | 58 | 59 | httpReadTimeout 60 | 3000 61 | Integer 62 | 63 | 64 | 65 | 66 | 67 | 68 | -------------------------------------------------------------------------------- /wowza-chaos-vhost/src/main/config/wowza_vhost_chaos_chaosv6/conf/StartupStreams.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /wowza-chaos-vhost/src/main/config/wowza_vhost_chaos_chaosv6/conf/Tune.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 12 | ${com.wowza.wms.TuningHeapSizeDevelopment} 13 | 14 | 22 | ${com.wowza.wms.TuningGarbageCollectorG1Default} 23 | 24 | 30 | 31 | -server 32 | -Djava.net.preferIPv4Stack=true 33 | 34 | 35 | 36 | 37 | 38 | 39 | -------------------------------------------------------------------------------- /wowza-chaos-vhost/src/main/config/wowza_vhost_chaos_chaosv6/conf/admin.password: -------------------------------------------------------------------------------- 1 | # Admin password file (format [username][space][password][space][group]) 2 | #username password group|group 3 | -------------------------------------------------------------------------------- /wowza-chaos-vhost/src/main/config/wowza_vhost_chaos_chaosv6/conf/chaos/wowza-modules.properties: -------------------------------------------------------------------------------- 1 | # 2 | # Property file for the CHAOS plugin for Wowza 3 | # 4 | # 5 | # ------------------------------------------------- 6 | # ---===<<< - General plugin properties - >>>===--- 7 | # ------------------------------------------------- 8 | # 9 | # General plugin properties 10 | # 11 | # Example: 12 | # 13 | # GeneralChaosV6ServerURL=https://api.prod.larm.fm/v6 14 | # 15 | GeneralChaosV6ServerURL=https://api.prod.larm.fm/v6 16 | # 17 | # ----------------------------------------------------------- 18 | # ---===<<< - Properties regarding authentication - >>>===--- 19 | # ----------------------------------------------------------- 20 | # 21 | # Standard Chaos-values. Do not change unless MCM has changes 22 | ValidationChaosV6ValidationMethod=LarmFile/CanAccess 23 | # 24 | # 25 | # --------------------------------------------------------------- 26 | # ---===<<< - Properties regarding statistics logging - >>>===--- 27 | # --------------------------------------------------------------- 28 | 29 | StatisticsLoggingJDBCDriver=org.postgresql.Driver 30 | StatisticsLoggingDBConnectionURL=jdbc:postgresql://triton:5432/larm-devel 31 | StatisticsLoggingDBUser=larm 32 | StatisticsLoggingDBPassword=larm1234 33 | -------------------------------------------------------------------------------- /wowza-chaos-vhost/src/main/config/wowza_vhost_chaos_chaosv6/conf/chaosnonapple/wowza-modules.properties: -------------------------------------------------------------------------------- 1 | # 2 | # Property file for the CHAOS plugin for Wowza 3 | # 4 | # 5 | # ------------------------------------------------- 6 | # ---===<<< - General plugin properties - >>>===--- 7 | # ------------------------------------------------- 8 | # 9 | # General plugin properties 10 | # 11 | # Example: 12 | # 13 | # GeneralChaosV6ServerURL=https://api.prod.larm.fm/v6 14 | # 15 | GeneralChaosV6ServerURL=https://api.prod.larm.fm/v6 16 | # 17 | # ----------------------------------------------------------- 18 | # ---===<<< - Properties regarding authentication - >>>===--- 19 | # ----------------------------------------------------------- 20 | # 21 | # Standard Chaos-values. Do not change unless MCM has changes 22 | ValidationChaosV6ValidationMethod=LarmFile/CanAccess 23 | # 24 | # 25 | # --------------------------------------------------------------- 26 | # ---===<<< - Properties regarding statistics logging - >>>===--- 27 | # --------------------------------------------------------------- 28 | 29 | StatisticsLoggingJDBCDriver=org.postgresql.Driver 30 | StatisticsLoggingDBConnectionURL=jdbc:postgresql://triton:5432/larm-devel 31 | StatisticsLoggingDBUser=larm 32 | StatisticsLoggingDBPassword=larm1234 33 | -------------------------------------------------------------------------------- /wowza-chaos-vhost/src/main/config/wowza_vhost_chaos_chaosv6/conf/clientaccesspolicy.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /wowza-chaos-vhost/src/main/config/wowza_vhost_chaos_chaosv6/conf/crossdomain.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /wowza-chaos-vhost/src/main/config/wowza_vhost_chaos_chaosv6_doms/conf/MediaCache.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | ${com.wowza.wms.TuningAuto} 7 | 8 | 9 | ${com.wowza.wms.TuningAuto} 10 | 11 | ${com.wowza.wms.TuningAuto} 12 | ${com.wowza.wms.TuningAuto} 13 | 10000 14 | 15 | true 16 | true 17 | false 18 | false 19 | true 20 | false 21 | 22 | 23 | 24 | 25 | default 26 | Default Store 27 | 28 | ${com.wowza.wms.context.ServerConfigHome}/mediacache 29 | 10G 30 | 24 31 | 24 32 | 1000 33 | 16M 34 | 64M 35 | 100 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | dvrorigin 46 | HTTP 47 | Default DVR source 48 | http:// 49 | dvrorigin/ 50 | com.wowza.wms.mediacache.impl.MediaCacheItemHTTPImpl 51 | 52 | 262144 53 | 1200000 54 | 600000 55 | true 56 | 50 57 | 58 | 59 | httpReadTimeout 60 | 3000 61 | Integer 62 | 63 | 64 | 65 | 66 | 67 | 68 | -------------------------------------------------------------------------------- /wowza-chaos-vhost/src/main/config/wowza_vhost_chaos_chaosv6_doms/conf/StartupStreams.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /wowza-chaos-vhost/src/main/config/wowza_vhost_chaos_chaosv6_doms/conf/Tune.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 12 | ${com.wowza.wms.TuningHeapSizeDevelopment} 13 | 14 | 22 | ${com.wowza.wms.TuningGarbageCollectorG1Default} 23 | 24 | 30 | 31 | -server 32 | -Djava.net.preferIPv4Stack=true 33 | 34 | 35 | 36 | 37 | 38 | 39 | -------------------------------------------------------------------------------- /wowza-chaos-vhost/src/main/config/wowza_vhost_chaos_chaosv6_doms/conf/admin.password: -------------------------------------------------------------------------------- 1 | # Admin password file (format [username][space][password][space][group]) 2 | #username password group|group 3 | -------------------------------------------------------------------------------- /wowza-chaos-vhost/src/main/config/wowza_vhost_chaos_chaosv6_doms/conf/chaos/wowza-modules.properties: -------------------------------------------------------------------------------- 1 | # 2 | # Property file for the CHAOS plugin for Wowza 3 | # 4 | # 5 | # ------------------------------------------------- 6 | # ---===<<< - General plugin properties - >>>===--- 7 | # ------------------------------------------------- 8 | # 9 | # General plugin properties 10 | # 11 | # Example: 12 | # 13 | # GeneralMCM3ServerURL=https://api.prod.stage.larm.fm/v6 14 | # 15 | GeneralChaosV6ServerURL=https://api.prod.larm.fm/v6 16 | # 17 | # ----------------------------------------------------------- 18 | # ---===<<< - Properties regarding authentication - >>>===--- 19 | # ----------------------------------------------------------- 20 | # 21 | # Standard MCM-values. Do not change unless MCM has changes 22 | ValidationChaosV6ValidationMethod=LarmFile/CanAccess 23 | # 24 | # 25 | # --------------------------------------------------------------- 26 | # ---===<<< - Properties regarding statistics logging - >>>===--- 27 | # --------------------------------------------------------------- 28 | 29 | StatisticsLoggingJDBCDriver=org.postgresql.Driver 30 | StatisticsLoggingDBConnectionURL=jdbc:postgresql://triton:5432/larm-devel 31 | StatisticsLoggingDBUser=larm 32 | StatisticsLoggingDBPassword=larm1234 33 | 34 | # --------------------------------------------------------------- 35 | # ---===<<< - Properties regarding content resolving - >>>===--- 36 | # --------------------------------------------------------------- 37 | # Number of characters to use for splitting content into directories. Example: if this is 2, the file 38 | # "hello.txt" will be in the path "h/e/hello.txt 39 | characterDirs=4 40 | characterDirsWidth=1 41 | 42 | # Pattern used for turning the content id into a file name. %s is replaced with the content id. 43 | filenameRegexPattern=%s\\.(mp4|mp3) 44 | 45 | # Type used by ticket checker and content resolver for identifying content 46 | presentationType=Stream 47 | 48 | -------------------------------------------------------------------------------- /wowza-chaos-vhost/src/main/config/wowza_vhost_chaos_chaosv6_doms/conf/chaosnonapple/wowza-modules.properties: -------------------------------------------------------------------------------- 1 | # 2 | # Property file for the CHAOS plugin for Wowza 3 | # 4 | # 5 | # ------------------------------------------------- 6 | # ---===<<< - General plugin properties - >>>===--- 7 | # ------------------------------------------------- 8 | # 9 | # General plugin properties 10 | # 11 | # Example: 12 | # 13 | # GeneralMCM3ServerURL=https://api.prod.stage.larm.fm/v6 14 | # 15 | GeneralChaosV6ServerURL=https://api.prod.larm.fm/v6 16 | # 17 | # ----------------------------------------------------------- 18 | # ---===<<< - Properties regarding authentication - >>>===--- 19 | # ----------------------------------------------------------- 20 | # 21 | # Standard MCM-values. Do not change unless MCM has changes 22 | ValidationChaosV6ValidationMethod=LarmFile/CanAccess 23 | # 24 | # 25 | # --------------------------------------------------------------- 26 | # ---===<<< - Properties regarding statistics logging - >>>===--- 27 | # --------------------------------------------------------------- 28 | 29 | StatisticsLoggingJDBCDriver=org.postgresql.Driver 30 | StatisticsLoggingDBConnectionURL=jdbc:postgresql://triton:5432/larm-devel 31 | StatisticsLoggingDBUser=larm 32 | StatisticsLoggingDBPassword=larm1234 33 | 34 | # --------------------------------------------------------------- 35 | # ---===<<< - Properties regarding content resolving - >>>===--- 36 | # --------------------------------------------------------------- 37 | # Number of characters to use for splitting content into directories. Example: if this is 2, the file 38 | # "hello.txt" will be in the path "h/e/hello.txt 39 | characterDirs=4 40 | characterDirsWidth=1 41 | 42 | # Pattern used for turning the content id into a file name. %s is replaced with the content id. 43 | filenameRegexPattern=%s\\.(mp4|mp3) 44 | 45 | # Type used by ticket checker and content resolver for identifying content 46 | presentationType=Stream 47 | 48 | -------------------------------------------------------------------------------- /wowza-chaos-vhost/src/main/config/wowza_vhost_chaos_chaosv6_doms/conf/clientaccesspolicy.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /wowza-chaos-vhost/src/main/config/wowza_vhost_chaos_chaosv6_doms/conf/crossdomain.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /wowza-chaos-vhost/src/main/config/wowza_vhost_chaos_chaosv6_doms_stageapi/conf/MediaCache.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | ${com.wowza.wms.TuningAuto} 7 | 8 | 9 | ${com.wowza.wms.TuningAuto} 10 | 11 | ${com.wowza.wms.TuningAuto} 12 | ${com.wowza.wms.TuningAuto} 13 | 10000 14 | 15 | true 16 | true 17 | false 18 | false 19 | true 20 | false 21 | 22 | 23 | 24 | 25 | default 26 | Default Store 27 | 28 | ${com.wowza.wms.context.ServerConfigHome}/mediacache 29 | 10G 30 | 24 31 | 24 32 | 1000 33 | 16M 34 | 64M 35 | 100 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | dvrorigin 46 | HTTP 47 | Default DVR source 48 | http:// 49 | dvrorigin/ 50 | com.wowza.wms.mediacache.impl.MediaCacheItemHTTPImpl 51 | 52 | 262144 53 | 1200000 54 | 600000 55 | true 56 | 50 57 | 58 | 59 | httpReadTimeout 60 | 3000 61 | Integer 62 | 63 | 64 | 65 | 66 | 67 | 68 | -------------------------------------------------------------------------------- /wowza-chaos-vhost/src/main/config/wowza_vhost_chaos_chaosv6_doms_stageapi/conf/StartupStreams.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /wowza-chaos-vhost/src/main/config/wowza_vhost_chaos_chaosv6_doms_stageapi/conf/Tune.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 12 | ${com.wowza.wms.TuningHeapSizeDevelopment} 13 | 14 | 22 | ${com.wowza.wms.TuningGarbageCollectorG1Default} 23 | 24 | 30 | 31 | -server 32 | -Djava.net.preferIPv4Stack=true 33 | 34 | 35 | 36 | 37 | 38 | 39 | -------------------------------------------------------------------------------- /wowza-chaos-vhost/src/main/config/wowza_vhost_chaos_chaosv6_doms_stageapi/conf/admin.password: -------------------------------------------------------------------------------- 1 | # Admin password file (format [username][space][password][space][group]) 2 | #username password group|group 3 | -------------------------------------------------------------------------------- /wowza-chaos-vhost/src/main/config/wowza_vhost_chaos_chaosv6_doms_stageapi/conf/chaos/wowza-modules.properties: -------------------------------------------------------------------------------- 1 | # 2 | # Property file for the CHAOS plugin for Wowza 3 | # 4 | # 5 | # ------------------------------------------------- 6 | # ---===<<< - General plugin properties - >>>===--- 7 | # ------------------------------------------------- 8 | # 9 | # General plugin properties 10 | # 11 | # Example: 12 | # 13 | # GeneralMCM3ServerURL=https://api.prod.stage.larm.fm/v6 14 | # 15 | GeneralChaosV6ServerURL=https://api.stage.larm.fm/v6 16 | # 17 | # ----------------------------------------------------------- 18 | # ---===<<< - Properties regarding authentication - >>>===--- 19 | # ----------------------------------------------------------- 20 | # 21 | # Standard MCM-values. Do not change unless MCM has changes 22 | ValidationChaosV6ValidationMethod=LarmFile/CanAccess 23 | # 24 | # 25 | # --------------------------------------------------------------- 26 | # ---===<<< - Properties regarding statistics logging - >>>===--- 27 | # --------------------------------------------------------------- 28 | 29 | StatisticsLoggingJDBCDriver=org.postgresql.Driver 30 | StatisticsLoggingDBConnectionURL=jdbc:postgresql://triton:5432/larm-devel 31 | StatisticsLoggingDBUser=larm 32 | StatisticsLoggingDBPassword=larm1234 33 | 34 | # --------------------------------------------------------------- 35 | # ---===<<< - Properties regarding content resolving - >>>===--- 36 | # --------------------------------------------------------------- 37 | # Number of characters to use for splitting content into directories. Example: if this is 2, the file 38 | # "hello.txt" will be in the path "h/e/hello.txt 39 | characterDirs=4 40 | characterDirsWidth=1 41 | 42 | # Pattern used for turning the content id into a file name. %s is replaced with the content id. 43 | filenameRegexPattern=%s\\.(mp4|mp3) 44 | 45 | # Type used by ticket checker and content resolver for identifying content 46 | presentationType=Stream 47 | 48 | -------------------------------------------------------------------------------- /wowza-chaos-vhost/src/main/config/wowza_vhost_chaos_chaosv6_doms_stageapi/conf/chaosnonapple/wowza-modules.properties: -------------------------------------------------------------------------------- 1 | # 2 | # Property file for the CHAOS plugin for Wowza 3 | # 4 | # 5 | # ------------------------------------------------- 6 | # ---===<<< - General plugin properties - >>>===--- 7 | # ------------------------------------------------- 8 | # 9 | # General plugin properties 10 | # 11 | # Example: 12 | # 13 | # GeneralMCM3ServerURL=https://api.prod.stage.larm.fm/v6 14 | # 15 | GeneralChaosV6ServerURL=https://api.stage.larm.fm/v6 16 | # 17 | # ----------------------------------------------------------- 18 | # ---===<<< - Properties regarding authentication - >>>===--- 19 | # ----------------------------------------------------------- 20 | # 21 | # Standard MCM-values. Do not change unless MCM has changes 22 | ValidationChaosV6ValidationMethod=LarmFile/CanAccess 23 | # 24 | # 25 | # --------------------------------------------------------------- 26 | # ---===<<< - Properties regarding statistics logging - >>>===--- 27 | # --------------------------------------------------------------- 28 | 29 | StatisticsLoggingJDBCDriver=org.postgresql.Driver 30 | StatisticsLoggingDBConnectionURL=jdbc:postgresql://triton:5432/larm-devel 31 | StatisticsLoggingDBUser=larm 32 | StatisticsLoggingDBPassword=larm1234 33 | 34 | # --------------------------------------------------------------- 35 | # ---===<<< - Properties regarding content resolving - >>>===--- 36 | # --------------------------------------------------------------- 37 | # Number of characters to use for splitting content into directories. Example: if this is 2, the file 38 | # "hello.txt" will be in the path "h/e/hello.txt 39 | characterDirs=4 40 | characterDirsWidth=1 41 | 42 | # Pattern used for turning the content id into a file name. %s is replaced with the content id. 43 | filenameRegexPattern=%s\\.(mp4|mp3) 44 | 45 | # Type used by ticket checker and content resolver for identifying content 46 | presentationType=Stream 47 | 48 | -------------------------------------------------------------------------------- /wowza-chaos-vhost/src/main/config/wowza_vhost_chaos_chaosv6_doms_stageapi/conf/clientaccesspolicy.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /wowza-chaos-vhost/src/main/config/wowza_vhost_chaos_chaosv6_doms_stageapi/conf/crossdomain.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /wowza-chaos-vhost/src/main/config/wowza_vhost_chaos_chaosv6_stageapi/conf/MediaCache.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | ${com.wowza.wms.TuningAuto} 7 | 8 | 9 | ${com.wowza.wms.TuningAuto} 10 | 11 | ${com.wowza.wms.TuningAuto} 12 | ${com.wowza.wms.TuningAuto} 13 | 10000 14 | 15 | true 16 | true 17 | false 18 | false 19 | true 20 | false 21 | 22 | 23 | 24 | 25 | default 26 | Default Store 27 | 28 | ${com.wowza.wms.context.ServerConfigHome}/mediacache 29 | 10G 30 | 24 31 | 24 32 | 1000 33 | 16M 34 | 64M 35 | 100 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | dvrorigin 46 | HTTP 47 | Default DVR source 48 | http:// 49 | dvrorigin/ 50 | com.wowza.wms.mediacache.impl.MediaCacheItemHTTPImpl 51 | 52 | 262144 53 | 1200000 54 | 600000 55 | true 56 | 50 57 | 58 | 59 | httpReadTimeout 60 | 3000 61 | Integer 62 | 63 | 64 | 65 | 66 | 67 | 68 | -------------------------------------------------------------------------------- /wowza-chaos-vhost/src/main/config/wowza_vhost_chaos_chaosv6_stageapi/conf/StartupStreams.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /wowza-chaos-vhost/src/main/config/wowza_vhost_chaos_chaosv6_stageapi/conf/Tune.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 12 | ${com.wowza.wms.TuningHeapSizeDevelopment} 13 | 14 | 22 | ${com.wowza.wms.TuningGarbageCollectorG1Default} 23 | 24 | 30 | 31 | -server 32 | -Djava.net.preferIPv4Stack=true 33 | 34 | 35 | 36 | 37 | 38 | 39 | -------------------------------------------------------------------------------- /wowza-chaos-vhost/src/main/config/wowza_vhost_chaos_chaosv6_stageapi/conf/admin.password: -------------------------------------------------------------------------------- 1 | # Admin password file (format [username][space][password][space][group]) 2 | #username password group|group 3 | -------------------------------------------------------------------------------- /wowza-chaos-vhost/src/main/config/wowza_vhost_chaos_chaosv6_stageapi/conf/chaos/wowza-modules.properties: -------------------------------------------------------------------------------- 1 | # 2 | # Property file for the CHAOS plugin for Wowza 3 | # 4 | # 5 | # ------------------------------------------------- 6 | # ---===<<< - General plugin properties - >>>===--- 7 | # ------------------------------------------------- 8 | # 9 | # General plugin properties 10 | # 11 | # Example: 12 | # 13 | # GeneralChaosV6ServerURL=https://api.prod.larm.fm/v6 14 | # 15 | GeneralChaosV6ServerURL=https://api.stage.larm.fm/v6 16 | # 17 | # ----------------------------------------------------------- 18 | # ---===<<< - Properties regarding authentication - >>>===--- 19 | # ----------------------------------------------------------- 20 | # 21 | # Standard Chaos-values. Do not change unless MCM has changes 22 | ValidationChaosV6ValidationMethod=LarmFile/CanAccess 23 | # 24 | # 25 | # --------------------------------------------------------------- 26 | # ---===<<< - Properties regarding statistics logging - >>>===--- 27 | # --------------------------------------------------------------- 28 | 29 | StatisticsLoggingJDBCDriver=org.postgresql.Driver 30 | StatisticsLoggingDBConnectionURL=jdbc:postgresql://triton:5432/larm-devel 31 | StatisticsLoggingDBUser=larm 32 | StatisticsLoggingDBPassword=larm1234 33 | -------------------------------------------------------------------------------- /wowza-chaos-vhost/src/main/config/wowza_vhost_chaos_chaosv6_stageapi/conf/chaosnonapple/wowza-modules.properties: -------------------------------------------------------------------------------- 1 | # 2 | # Property file for the CHAOS plugin for Wowza 3 | # 4 | # 5 | # ------------------------------------------------- 6 | # ---===<<< - General plugin properties - >>>===--- 7 | # ------------------------------------------------- 8 | # 9 | # General plugin properties 10 | # 11 | # Example: 12 | # 13 | # GeneralChaosV6ServerURL=https://api.prod.larm.fm/v6 14 | # 15 | GeneralChaosV6ServerURL=https://api.stage.larm.fm/v6 16 | # 17 | # ----------------------------------------------------------- 18 | # ---===<<< - Properties regarding authentication - >>>===--- 19 | # ----------------------------------------------------------- 20 | # 21 | # Standard Chaos-values. Do not change unless MCM has changes 22 | ValidationChaosV6ValidationMethod=LarmFile/CanAccess 23 | # 24 | # 25 | # --------------------------------------------------------------- 26 | # ---===<<< - Properties regarding statistics logging - >>>===--- 27 | # --------------------------------------------------------------- 28 | 29 | StatisticsLoggingJDBCDriver=org.postgresql.Driver 30 | StatisticsLoggingDBConnectionURL=jdbc:postgresql://triton:5432/larm-devel 31 | StatisticsLoggingDBUser=larm 32 | StatisticsLoggingDBPassword=larm1234 33 | -------------------------------------------------------------------------------- /wowza-chaos-vhost/src/main/config/wowza_vhost_chaos_chaosv6_stageapi/conf/clientaccesspolicy.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /wowza-chaos-vhost/src/main/config/wowza_vhost_chaos_chaosv6_stageapi/conf/crossdomain.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /wowza-chaosv6-authorization-module/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4.0.0 4 | 5 | 6 | dk.statsbiblioteket.medieplatform 7 | wowza-modules 8 | 4.8-SNAPSHOT 9 | 10 | 11 | wowza-chaosv6-authorization-module 12 | 13 | 14 | 15 | dk.statsbiblioteket.medieplatform 16 | wowza-common 17 | 18 | 19 | 20 | dk.statsbiblioteket.medieplatform 21 | wowza-mcm-authorization-module 22 | 23 | 24 | 25 | com.wms 26 | wms-server 27 | provided 28 | 29 | 30 | 31 | com.wms 32 | wms-bootstrap 33 | provided 34 | 35 | 36 | 37 | com.wms 38 | wms-core 39 | provided 40 | 41 | 42 | 43 | com.wms 44 | wms-transcoder 45 | provided 46 | 47 | 48 | 49 | com.wms 50 | wms-rest 51 | provided 52 | 53 | 54 | 55 | com.wms 56 | wms-pushpublish 57 | provided 58 | 59 | 60 | 61 | log4j 62 | log4j 63 | provided 64 | 65 | 66 | 67 | org.bouncycastle 68 | bcprov-jdk15on 69 | provided 70 | 71 | 72 | 73 | commons-lang 74 | commons-lang 75 | provided 76 | 77 | 78 | 79 | org.junit.jupiter 80 | junit-jupiter-engine 81 | test 82 | 83 | 84 | 85 | org.mockito 86 | mockito-core 87 | test 88 | 89 | 90 | 91 | -------------------------------------------------------------------------------- /wowza-chaosv6-authorization-module/src/main/java/dk/statsbiblioteket/medieplatform/wowza/plugin/authentication/ChaosV6API.java: -------------------------------------------------------------------------------- 1 | package dk.statsbiblioteket.medieplatform.wowza.plugin.authentication; 2 | 3 | import com.wowza.wms.logging.WMSLogger; 4 | 5 | import dk.statsbiblioteket.medieplatform.wowza.plugin.authentication.model.MCMOutputException; 6 | import dk.statsbiblioteket.medieplatform.wowza.plugin.utilities.StringAndTextUtil; 7 | 8 | import java.io.IOException; 9 | import java.io.InputStream; 10 | import java.net.MalformedURLException; 11 | import java.net.URL; 12 | import java.net.URLEncoder; 13 | 14 | /** 15 | * Methods used when calling the CHAOS v6 API 16 | */ 17 | public class ChaosV6API { 18 | 19 | private String connectionURLString; 20 | private String validationMethodAtServer; 21 | private WMSLogger logger; 22 | 23 | public ChaosV6API(String connectionURLString, String validationMethodAtServer, WMSLogger logger) { 24 | this.connectionURLString = connectionURLString; 25 | this.validationMethodAtServer = validationMethodAtServer; 26 | this.logger = logger; 27 | } 28 | 29 | /** 30 | * Call chaos to check session is valid. NOTE: In debug mode the call is made twice. 31 | * 32 | * @param sessionID CHAOS Session ID 33 | * @param objectID CHAOS Object ID 34 | * @param filePath Path of file 35 | * @return The output from CHAOS. 36 | * 37 | * @throws IOException On trouble connection to CHAOS 38 | * @throws MalformedURLException On bad URL connecting to CHAOS 39 | * @throws dk.statsbiblioteket.medieplatform.wowza.plugin.authentication.model.MCMOutputException error 40 | */ 41 | public InputStream larmValidateSession(String sessionID, String objectID, String filePath) 42 | throws IOException, MalformedURLException, MCMOutputException { 43 | String urlStringToCHAOS = this.connectionURLString + "/" + this.validationMethodAtServer + "?" + "sessionGUID=" + sessionID 44 | + "&" + "objectId=" + objectID + "&" + "filePath=" + URLEncoder.encode(filePath, "UTF-8"); 45 | 46 | InputStream in; 47 | if (logger.isDebugEnabled()) { 48 | logger.debug("CHAOS URL:" + urlStringToCHAOS); 49 | InputStream inDebug = new URL(urlStringToCHAOS).openConnection().getInputStream(); 50 | logger.debug("Returned from CHAOS: " + StringAndTextUtil.convertStreamToString(inDebug)); 51 | } 52 | in = new URL(urlStringToCHAOS).openConnection().getInputStream(); 53 | return in; 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /wowza-chaosv6-authorization-module/src/main/java/dk/statsbiblioteket/medieplatform/wowza/plugin/authentication/ChaosV6SessionAndFilenameValidater.java: -------------------------------------------------------------------------------- 1 | package dk.statsbiblioteket.medieplatform.wowza.plugin.authentication; 2 | 3 | import com.wowza.wms.application.IApplicationInstance; 4 | import com.wowza.wms.logging.WMSLogger; 5 | import org.w3c.dom.Document; 6 | import org.w3c.dom.NodeList; 7 | 8 | import dk.statsbiblioteket.medieplatform.wowza.plugin.authentication.model.MCMOutputException; 9 | import dk.statsbiblioteket.medieplatform.wowza.plugin.authentication.model.MCMSessionAndFilenameValidater; 10 | import dk.statsbiblioteket.medieplatform.wowza.plugin.authentication.model.SessionAndFilenameValidaterIF; 11 | 12 | import javax.xml.parsers.DocumentBuilder; 13 | import javax.xml.parsers.DocumentBuilderFactory; 14 | import java.io.FileNotFoundException; 15 | import java.io.IOException; 16 | import java.io.InputStream; 17 | import java.net.MalformedURLException; 18 | 19 | /** 20 | * Call CHAOS to see if session is valid and lookup object from the GUID. 21 | */ 22 | public class ChaosV6SessionAndFilenameValidater extends MCMSessionAndFilenameValidater { 23 | 24 | private final DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance(); 25 | private ChaosV6API chaosV6API; 26 | 27 | /** 28 | * Reads server connection configuration from property-file. Property file 29 | * is expected to be at "<VHost_HOME>/<propertyFilePath>" 30 | * 31 | * Example of content in property file could be: 32 | * 33 | * GeneralChaosV6ServerURL=http://api.stage.larm.fm/v6 34 | * ValidationChaosV6ValidationMethod=LarmFile/CanAccess 35 | * 36 | * @param logger the logger 37 | * @param connectionURLString connectionurl 38 | * @param validationMethodAtServer validation method 39 | * @param chaosV6API chaosv6api 40 | */ 41 | public ChaosV6SessionAndFilenameValidater(WMSLogger logger, String connectionURLString, 42 | String validationMethodAtServer, ChaosV6API chaosV6API) { 43 | super(logger, connectionURLString, validationMethodAtServer); 44 | this.chaosV6API = chaosV6API; 45 | } 46 | 47 | /** 48 | * Validate rights to play file. 49 | * 50 | * @see SessionAndFilenameValidaterIF#validateRightsToPlayFile(java.lang.String, java.lang.String, java.lang.String) 51 | */ 52 | @Override 53 | public boolean validateRightsToPlayFile(String sessionID, String objectID, String filenameAndPath) 54 | throws MalformedURLException, IOException, MCMOutputException { 55 | if (sessionID == null || objectID == null || filenameAndPath == null) { 56 | throw new IllegalArgumentException( 57 | "WARNING: At least one of the arguments is null: " + "(sessionID=" + sessionID + ", objectID=" 58 | + objectID + ", filename=" + filenameAndPath + ")"); 59 | } 60 | boolean isAllowedToStream; 61 | try (InputStream in = chaosV6API.larmValidateSession(sessionID, objectID, filenameAndPath)) { 62 | isAllowedToStream = parseResult(in); 63 | } 64 | if (!isAllowedToStream) { 65 | logger.warn("CHAOS validation. Did not validate right to play file."); 66 | } 67 | logger.debug("Validated stream using parameters sessionID=\" + sessionID + \", objectID=\"\n" 68 | + " + objectID + \", filename=\" + filenameAndPath + \""); 69 | return isAllowedToStream; 70 | } 71 | 72 | /** 73 | * Check if the CHAOS result allows the stream to play, by looking for the "WasSuccess"-element in the output. 74 | * @param in The output from CHAOS. 75 | * @return Whether the "WasSuccess"-element contains true. 76 | * @throws MCMOutputException If the output cannot be parsed or does not contain a "WasSuccess"-element. 77 | */ 78 | protected boolean parseResult(InputStream in) throws MCMOutputException { 79 | Document dom; 80 | try { 81 | DocumentBuilder db = documentBuilderFactory.newDocumentBuilder(); 82 | dom = db.parse(in); 83 | } catch (Exception e) { 84 | throw new MCMOutputException("Unable to parse CHAOS result", e); 85 | } 86 | NodeList nodelist = dom.getDocumentElement().getElementsByTagName("WasSuccess"); 87 | if (nodelist != null && nodelist.getLength() > 0) { 88 | return Boolean.parseBoolean(nodelist.item(0).getFirstChild().getNodeValue().trim()); 89 | } else { 90 | throw new MCMOutputException("No 'WasSuccess' element in CHAOS result"); 91 | } 92 | } 93 | } 94 | -------------------------------------------------------------------------------- /wowza-chaosv6-authorization-module/src/test/java/dk/statsbiblioteket/medieplatform/wowza/plugin/authentication/model/ChaosV6SessionAndFilenameValidaterTest.java: -------------------------------------------------------------------------------- 1 | package dk.statsbiblioteket.medieplatform.wowza.plugin.authentication.model; 2 | 3 | import java.io.IOException; 4 | 5 | import com.wowza.wms.logging.WMSLogger; 6 | import com.wowza.wms.logging.WMSLoggerFactory; 7 | 8 | import dk.statsbiblioteket.medieplatform.wowza.plugin.authentication.ChaosV6API; 9 | import dk.statsbiblioteket.medieplatform.wowza.plugin.authentication.ChaosV6SessionAndFilenameValidater; 10 | 11 | import org.junit.jupiter.api.AfterEach; 12 | import org.junit.jupiter.api.BeforeEach; 13 | import org.junit.jupiter.api.Test; 14 | import static org.junit.jupiter.api.Assertions.*; 15 | import static org.mockito.ArgumentMatchers.*; 16 | import static org.mockito.Mockito.mock; 17 | import static org.mockito.Mockito.when; 18 | 19 | /** Test chaos V6 authorization validator */ 20 | public class ChaosV6SessionAndFilenameValidaterTest { 21 | 22 | @Test 23 | public void testValidateRightsToPlayFileSuccess() throws MCMOutputException, IOException { 24 | WMSLogger wmsLogger = WMSLoggerFactory.getLogger(this.getClass()); 25 | ChaosV6API chaosV6API = mock(ChaosV6API.class); 26 | when(chaosV6API.larmValidateSession(anyString(), anyString(), anyString())).thenReturn(Thread.currentThread().getContextClassLoader().getResourceAsStream("test_data_chaosv6_output_full.xml")); 27 | 28 | ChaosV6SessionAndFilenameValidater validater = new ChaosV6SessionAndFilenameValidater(wmsLogger, "connectionURLString", "validationMethodAtServer", 29 | chaosV6API); 30 | boolean doesValidate = validater.validateRightsToPlayFile("a", "b", "c"); 31 | 32 | assertEquals(true, doesValidate, "Filename validation:"); 33 | } 34 | 35 | @Test 36 | public void testValidateRightsToPlayFileFailure() throws MCMOutputException, IOException { 37 | WMSLogger wmsLogger = WMSLoggerFactory.getLogger(this.getClass()); 38 | ChaosV6API chaosV6API = mock(ChaosV6API.class); 39 | when(chaosV6API.larmValidateSession(anyString(), anyString(), anyString())).thenReturn(Thread.currentThread().getContextClassLoader().getResourceAsStream("test_data_chaosv6_output_invalid_session.xml")); 40 | 41 | ChaosV6SessionAndFilenameValidater validater = new ChaosV6SessionAndFilenameValidater(wmsLogger, "connectionURLString", "validationMethodAtServer", 42 | chaosV6API); 43 | boolean doesValidate = validater.validateRightsToPlayFile("a", "b", "c"); 44 | 45 | assertEquals(false, doesValidate, "Filename validation:"); 46 | } 47 | 48 | @Test 49 | public void testValidateRightsToPlayFileError() throws MCMOutputException, IOException { 50 | WMSLogger wmsLogger = WMSLoggerFactory.getLogger(this.getClass()); 51 | ChaosV6API chaosV6API = mock(ChaosV6API.class); 52 | when(chaosV6API.larmValidateSession(anyString(), anyString(), anyString())).thenReturn(Thread.currentThread().getContextClassLoader().getResourceAsStream("test_data_invalid_output.xml")); 53 | 54 | ChaosV6SessionAndFilenameValidater validater = new ChaosV6SessionAndFilenameValidater(wmsLogger, "connectionURLString", "validationMethodAtServer", 55 | chaosV6API); 56 | try { 57 | validater.validateRightsToPlayFile("a", "b", "c"); 58 | } catch (MCMOutputException e) { 59 | //expected 60 | return; 61 | } 62 | fail("Should throw exception"); 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /wowza-chaosv6-authorization-module/src/test/resources/test_data_chaosv6_output_full.xml: -------------------------------------------------------------------------------- 1 | True -------------------------------------------------------------------------------- /wowza-chaosv6-authorization-module/src/test/resources/test_data_chaosv6_output_invalid_session.xml: -------------------------------------------------------------------------------- 1 | False -------------------------------------------------------------------------------- /wowza-chaosv6-authorization-module/src/test/resources/test_data_invalid_output.xml: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /wowza-common/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4.0.0 4 | 5 | 6 | dk.statsbiblioteket.medieplatform 7 | wowza-modules 8 | 4.8-SNAPSHOT 9 | 10 | 11 | wowza-common 12 | 13 | 14 | 15 | dk.statsbiblioteket.medieplatform.ticketsystem 16 | ticket-system-common 17 | 18 | 19 | org.junit.jupiter 20 | junit-jupiter-engine 21 | test 22 | 23 | 24 | log4j 25 | log4j 26 | provided 27 | 28 | 29 | com.wms 30 | wms-server 31 | provided 32 | 33 | 34 | com.wms 35 | wms-core 36 | provided 37 | 38 | 39 | com.wms 40 | wms-bootstrap 41 | provided 42 | 43 | 44 | com.wms 45 | wms-transcoder 46 | provided 47 | 48 | 49 | com.wms 50 | wms-rest 51 | provided 52 | 53 | 54 | com.wms 55 | wms-pushpublish 56 | provided 57 | 58 | 59 | org.bouncycastle 60 | bcprov-jdk15on 61 | provided 62 | 63 | 64 | commons-lang 65 | commons-lang 66 | provided 67 | 68 | 69 | -------------------------------------------------------------------------------- /wowza-common/src/main/java/dk/statsbiblioteket/medieplatform/wowza/plugin/ticket/TicketToolInterface.java: -------------------------------------------------------------------------------- 1 | package dk.statsbiblioteket.medieplatform.wowza.plugin.ticket; 2 | 3 | import dk.statsbiblioteket.medieplatform.ticketsystem.Ticket; 4 | 5 | /** Resolve a ticket from a ticket ID. */ 6 | public interface TicketToolInterface { 7 | /** Resolve a ticket from a ticket ID. 8 | * 9 | * @param ticketID The ID of the ticket. 10 | * @return The resolved ticket. 11 | */ 12 | public abstract Ticket resolveTicket(String ticketID); 13 | } -------------------------------------------------------------------------------- /wowza-common/src/main/java/dk/statsbiblioteket/medieplatform/wowza/plugin/utilities/ConfigReader.java: -------------------------------------------------------------------------------- 1 | package dk.statsbiblioteket.medieplatform.wowza.plugin.utilities; 2 | 3 | import java.io.File; 4 | import java.io.FileInputStream; 5 | import java.io.FileNotFoundException; 6 | import java.io.IOException; 7 | import java.io.InputStream; 8 | import java.util.Arrays; 9 | import java.util.HashSet; 10 | import java.util.Properties; 11 | import java.util.Set; 12 | 13 | /** 14 | * Read configuration. 15 | * This reads configuration file from a given path. 16 | */ 17 | public class ConfigReader { 18 | 19 | private Properties properties; 20 | 21 | /** 22 | * Read configuration from given path. 23 | * Fails if list of required properties are not defined. 24 | * @param path The path to read properties from. 25 | * @param requiredProperties If given properties are not found, throws exception. 26 | * 27 | * @throws RuntimeException if properties are not set. 28 | * @throws IOException on trouble reading property from path. 29 | */ 30 | public ConfigReader(String path, String... requiredProperties) throws IOException { 31 | 32 | properties = new Properties(); 33 | 34 | InputStream props = this.getClass().getClassLoader().getResourceAsStream(path); 35 | if (props == null) { 36 | throw new FileNotFoundException("property file '" + path + "' not found in the classpath"); 37 | } 38 | properties.load(props); 39 | checkProperties(requiredProperties); 40 | } 41 | 42 | public ConfigReader(File file, String... requiredProperties) throws IOException { 43 | properties = new Properties(); 44 | properties.load(new FileInputStream(file)); 45 | checkProperties(requiredProperties); 46 | } 47 | 48 | /** 49 | * Read property. 50 | * @param key The property key. 51 | * @return The property value. 52 | */ 53 | public String get(String key) { 54 | return properties.getProperty(key); 55 | } 56 | 57 | /** 58 | * Read property. 59 | * @param key The property key. 60 | * @param defaultValue the default value if the property is not found 61 | * @return The property value, or defaultValue if key is not set. 62 | */ 63 | public String get(String key, String defaultValue) { 64 | return properties.getProperty(key, defaultValue); 65 | } 66 | 67 | /** 68 | * Throw exception if given property keys are not set. 69 | * @param propertyKeys Properties that must be set. 70 | * 71 | * @throws RuntimeException if properties are not set. 72 | */ 73 | private void checkProperties(String[] propertyKeys) { 74 | Set keysLeft = new HashSet(); 75 | keysLeft.addAll(Arrays.asList(propertyKeys)); 76 | for (String key : propertyKeys) { 77 | if (properties.getProperty(key) != null) { 78 | keysLeft.remove(key); 79 | } 80 | } 81 | if (!keysLeft.isEmpty()) { 82 | String message = "Missing keys:"; 83 | for (String key:keysLeft) { 84 | message += " " + key; 85 | } 86 | throw new RuntimeException("Missing properties.\n" + message); 87 | } 88 | } 89 | } 90 | -------------------------------------------------------------------------------- /wowza-common/src/main/java/dk/statsbiblioteket/medieplatform/wowza/plugin/utilities/IllegallyFormattedQueryStringException.java: -------------------------------------------------------------------------------- 1 | package dk.statsbiblioteket.medieplatform.wowza.plugin.utilities; 2 | 3 | /** 4 | * Exception thrown on trouble extracting a key from a query string. 5 | */ 6 | public class IllegallyFormattedQueryStringException extends Exception { 7 | 8 | public IllegallyFormattedQueryStringException(String message) { 9 | super(message); 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /wowza-common/src/main/java/dk/statsbiblioteket/medieplatform/wowza/plugin/utilities/StringAndTextUtil.java: -------------------------------------------------------------------------------- 1 | package dk.statsbiblioteket.medieplatform.wowza.plugin.utilities; 2 | 3 | import dk.statsbiblioteket.medieplatform.ticketsystem.Ticket; 4 | import dk.statsbiblioteket.medieplatform.wowza.plugin.ticket.TicketToolInterface; 5 | 6 | import java.io.BufferedReader; 7 | import java.io.IOException; 8 | import java.io.InputStream; 9 | import java.io.InputStreamReader; 10 | import java.io.Reader; 11 | import java.io.StringWriter; 12 | import java.io.Writer; 13 | import java.util.StringTokenizer; 14 | 15 | /** 16 | * Utility methods for working with Wowza strings. 17 | */ 18 | public class StringAndTextUtil { 19 | /** 20 | * Given a query string, return the value for a given key. Throws exception if key is not set. 21 | * @param key The key to look up in query string. 22 | * @param queryString The query string to read key from. 23 | * @return The value of the given key. 24 | * 25 | * @throws IllegallyFormattedQueryStringException If key is not set in query string, or if query string has bad 26 | * format. 27 | */ 28 | public static String extractValueFromQueryStringAndKey(String key, 29 | String queryString) throws IllegallyFormattedQueryStringException { 30 | if (queryString == null) { 31 | queryString = ""; 32 | } 33 | // Some players add a / to the query string. Strip it 34 | if (queryString.endsWith("/")) { 35 | queryString = queryString.substring(0, queryString.length() - 1); 36 | } 37 | StringTokenizer queryItems = new StringTokenizer(queryString, "&"); 38 | while (queryItems.hasMoreTokens()) { 39 | String queryParameter = queryItems.nextToken(); 40 | StringTokenizer paramTokenizer = new StringTokenizer(queryParameter, "="); 41 | if (paramTokenizer.countTokens() != 2) { 42 | //parameters not of the form a=b are ignored 43 | continue; 44 | } 45 | String currentKey = paramTokenizer.nextToken(); 46 | String currentValue = paramTokenizer.nextToken(); 47 | if (currentKey.equalsIgnoreCase(key)) { 48 | return currentValue; 49 | } 50 | } 51 | throw new IllegallyFormattedQueryStringException( 52 | "Expected key '" + key + "' not found in query string" + queryString + "'"); 53 | } 54 | 55 | /** 56 | * Given an input stream, read contents into a string using UTF-8 as charset. 57 | * @param is Input stream 58 | * @return Contents of input stream. 59 | * @throws IOException On trouble reading from input stream. 60 | */ 61 | public static String convertStreamToString(InputStream is) 62 | throws IOException { 63 | /* 64 | * To convert the InputStream to String we use the 65 | * Reader.read(char[] buffer) method. We iterate until the 66 | * Reader return -1 which means there's no more data to 67 | * read. We use the StringWriter class to produce the string. 68 | */ 69 | if (is != null) { 70 | Writer writer = new StringWriter(); 71 | 72 | char[] buffer = new char[1024]; 73 | try { 74 | Reader reader = new BufferedReader( 75 | new InputStreamReader(is, "UTF-8")); 76 | int n; 77 | while ((n = reader.read(buffer)) != -1) { 78 | writer.write(buffer, 0, n); 79 | } 80 | } finally { 81 | is.close(); 82 | } 83 | return writer.toString(); 84 | } else { 85 | return ""; 86 | } 87 | } 88 | 89 | /** 90 | * Get ticket extracted from the query string. 91 | * @param queryString Query string from which to extract the ticket. 92 | * @param ticketTool Ticket tool used for looking up tickets. 93 | * @return Ticket extracted 94 | * @throws IllegallyFormattedQueryStringException If query string is illegally formatted 95 | */ 96 | public static Ticket getTicket(String queryString, TicketToolInterface ticketTool) 97 | throws IllegallyFormattedQueryStringException { 98 | String ticketID = extractValueFromQueryStringAndKey("ticket", queryString); 99 | return ticketTool.resolveTicket(ticketID); 100 | } 101 | } 102 | -------------------------------------------------------------------------------- /wowza-common/src/test/java/dk/statsbiblioteket/medieplatform/wowza/plugin/utilities/StringAndTextUtilTest.java: -------------------------------------------------------------------------------- 1 | package dk.statsbiblioteket.medieplatform.wowza.plugin.utilities; 2 | 3 | import com.wowza.wms.logging.WMSLogger; 4 | import com.wowza.wms.logging.WMSLoggerFactory; 5 | 6 | import java.io.FileNotFoundException; 7 | import java.io.IOException; 8 | 9 | import org.junit.jupiter.api.Test; 10 | import static org.junit.jupiter.api.Assertions.*; 11 | 12 | 13 | /** 14 | * Tests for extracting values from querystring. 15 | */ 16 | public class StringAndTextUtilTest { 17 | private String param1 = "param1Key=param1Value"; 18 | private String param2 = "param1Key=param2Value"; 19 | private String param3 = "param1Key=param3Value"; 20 | 21 | private WMSLogger logger; 22 | 23 | private String validSessionID; 24 | private String validObjectID; 25 | 26 | public StringAndTextUtilTest() throws FileNotFoundException, IOException { 27 | super(); 28 | this.logger = WMSLoggerFactory.getLogger(this.getClass()); 29 | this.validSessionID = "5F95E509-FD84-4570-9382-FEC5481E342F"; 30 | this.validObjectID = "976"; 31 | logger.info("Ready for test."); 32 | } 33 | 34 | @Test 35 | public void testExtractValueFromQueryStringAndKeyNonExistingKey() { 36 | String queryString = "ObjectID=" + validObjectID + "&SessionID=" + validSessionID; 37 | String key = "nonexistingKey"; 38 | try { 39 | StringAndTextUtil.extractValueFromQueryStringAndKey(key, queryString); 40 | fail("This statement should not be reached"); 41 | } catch (IllegallyFormattedQueryStringException e) { 42 | // Expected 43 | } 44 | } 45 | 46 | @Test 47 | public void testExtractValueFromQueryStringAndKeyObjectID() throws IllegallyFormattedQueryStringException { 48 | String queryString = "ObjectID=" + validObjectID + "&SessionID=" + validSessionID; 49 | String key = "ObjectID"; 50 | String value = StringAndTextUtil.extractValueFromQueryStringAndKey(key, queryString); 51 | assertEquals(validObjectID, value, "Unexpected return value."); 52 | } 53 | 54 | @Test 55 | public void testExtractValueFromQueryStringAndKeySessionID() throws IllegallyFormattedQueryStringException { 56 | String queryString = "ObjectID=" + validObjectID + "&SessionID=" + validSessionID; 57 | String key = "SessionID"; 58 | String value = StringAndTextUtil.extractValueFromQueryStringAndKey(key, queryString); 59 | assertEquals(validSessionID, value, "Unexpected return value."); 60 | } 61 | 62 | @Test 63 | public void testTicketFirstInQuery() throws IllegallyFormattedQueryStringException { 64 | // Setup environment 65 | String ticketIDOrig = "123456abcd"; 66 | String ticketParam = "ticket=" + ticketIDOrig; 67 | String queryString = ticketParam + "&" + param1 + "&" + param2 + "&" + param3; 68 | String ticketIDExtract = StringAndTextUtil.extractValueFromQueryStringAndKey("ticket", queryString); 69 | assertEquals(ticketIDOrig, ticketIDExtract); 70 | } 71 | 72 | @Test 73 | public void testTicketSecondInQuery() throws IllegallyFormattedQueryStringException { 74 | // Setup environment 75 | String ticketIDOrig = "123456abcd"; 76 | String ticketParam = "ticket=" + ticketIDOrig; 77 | String queryString = param1 + "&" + ticketParam + "&" + param2 + "&" + param3; 78 | String ticketIDExtract = StringAndTextUtil.extractValueFromQueryStringAndKey("ticket", queryString); 79 | assertEquals(ticketIDOrig, ticketIDExtract); 80 | } 81 | 82 | @Test 83 | public void testTicketLastInQuery() throws IllegallyFormattedQueryStringException { 84 | // Setup environment 85 | String ticketIDOrig = "123456abcd"; 86 | String ticketParam = "ticket=" + ticketIDOrig; 87 | String queryString = param1 + "&" + param2 + "&" + param3 + "&" + ticketParam; 88 | String ticketIDExtract = StringAndTextUtil.extractValueFromQueryStringAndKey("ticket", queryString); 89 | assertEquals(ticketIDOrig, ticketIDExtract); 90 | } 91 | 92 | @Test 93 | public void testTicketOnlyInQuery() throws IllegallyFormattedQueryStringException { 94 | // Setup environment 95 | String ticketIDOrig = "123456abcd"; 96 | String ticketParam = "ticket=" + ticketIDOrig; 97 | String queryString = ticketParam; 98 | String ticketIDExtract = StringAndTextUtil.extractValueFromQueryStringAndKey("ticket", queryString); 99 | assertEquals(ticketIDOrig, ticketIDExtract); 100 | } 101 | 102 | @Test 103 | public void testNoTicketInQuery() { 104 | // Setup environment 105 | String queryString = param1 + "&" + param2 + "&" + param3; 106 | try { 107 | StringAndTextUtil.extractValueFromQueryStringAndKey("ticket", queryString); 108 | fail("This statement should not be reached!"); 109 | } catch (IllegallyFormattedQueryStringException e) { 110 | // Expected behavior 111 | } 112 | } 113 | } 114 | -------------------------------------------------------------------------------- /wowza-content-resolver-module/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4.0.0 4 | 5 | 6 | dk.statsbiblioteket.medieplatform 7 | wowza-modules 8 | 4.8-SNAPSHOT 9 | 10 | 11 | wowza-content-resolver-module 12 | 13 | 14 | 15 | 16 | dk.statsbiblioteket.medieplatform 17 | wowza-common 18 | 19 | 20 | 21 | dk.statsbiblioteket.medieplatform 22 | content-resolver-lib 23 | jar 24 | 25 | 26 | 27 | com.wms 28 | wms-server 29 | provided 30 | 31 | 32 | 33 | com.wms 34 | wms-bootstrap 35 | provided 36 | 37 | 38 | 39 | com.wms 40 | wms-core 41 | provided 42 | 43 | 44 | 45 | log4j 46 | log4j 47 | provided 48 | 49 | 50 | 51 | org.bouncycastle 52 | bcprov-jdk15on 53 | provided 54 | 55 | 56 | 57 | commons-lang 58 | commons-lang 59 | provided 60 | 61 | 62 | 63 | com.wms 64 | wms-transcoder 65 | provided 66 | 67 | 68 | 69 | com.wms 70 | wms-rest 71 | provided 72 | 73 | 74 | 75 | com.wms 76 | wms-stream-publish 77 | provided 78 | 79 | 80 | 81 | com.wms 82 | wms-sourcecontrol 83 | provided 84 | 85 | 86 | 87 | com.wms 88 | wms-webrtc 89 | provided 90 | 91 | 92 | 93 | com.wms 94 | wms-mediacache 95 | provided 96 | 97 | 98 | 99 | com.wms 100 | wms-pushpublish 101 | provided 102 | 103 | 104 | 105 | org.junit.jupiter 106 | junit-jupiter-engine 107 | test 108 | 109 | 110 | org.mockito 111 | mockito-core 112 | test 113 | 114 | 115 | -------------------------------------------------------------------------------- /wowza-content-resolver-module/src/main/java/dk/statsbiblioteket/medieplatform/wowza/plugin/ContentResolverMapper.java: -------------------------------------------------------------------------------- 1 | package dk.statsbiblioteket.medieplatform.wowza.plugin; 2 | 3 | import com.wowza.wms.logging.WMSLogger; 4 | import com.wowza.wms.logging.WMSLoggerFactory; 5 | import com.wowza.wms.stream.IMediaStream; 6 | import com.wowza.wms.stream.IMediaStreamFileMapper; 7 | import com.wowza.wms.stream.MediaStreamFileMapperBase; 8 | 9 | import dk.statsbiblioteket.medieplatform.contentresolver.lib.ContentResolver; 10 | import dk.statsbiblioteket.medieplatform.contentresolver.model.Resource; 11 | 12 | import java.io.File; 13 | import java.util.List; 14 | 15 | /** 16 | * This class is used to let the user see the correct file, given an identifier. 17 | */ 18 | public class ContentResolverMapper extends MediaStreamFileMapperBase implements IMediaStreamFileMapper { 19 | 20 | private static final File FILE_NOT_FOUND_NON_EXISTENT_FILE = new File("file_not_found"); 21 | private final WMSLogger logger; 22 | private String presentationType; 23 | private final IMediaStreamFileMapper defaultMapper; 24 | private final ContentResolver contentResolver; 25 | 26 | /** 27 | * Initialise a content resolver mapper. 28 | * 29 | * @param presentationType The presentation type used by the content resolver. 30 | * @param defaultMapper The normal file mapper, used for passing on unresolved ids. 31 | * @param contentResolver The content resolver used for resolving ids to file names. 32 | */ 33 | public ContentResolverMapper(String presentationType, IMediaStreamFileMapper defaultMapper, 34 | ContentResolver contentResolver) { 35 | super(); 36 | this.presentationType = presentationType; 37 | this.defaultMapper = defaultMapper; 38 | this.contentResolver = contentResolver; 39 | this.logger = WMSLoggerFactory.getLogger(this.getClass()); 40 | } 41 | 42 | /** 43 | * This method is invoked when Wowza tries to figure out which file to play 44 | * @param stream the stream requested 45 | * @return The file to stream. 46 | */ 47 | @Override 48 | public File streamToFileForRead(IMediaStream stream) { 49 | logger.trace("streamToFileForRead(IMediaStream stream=" + stream + ")"); 50 | String name = stream.getName(); 51 | String ext = stream.getExt(); 52 | String query = stream.getQueryStr(); 53 | return streamToFileForRead(stream, name, ext, query); 54 | } 55 | 56 | /** 57 | * This method is invoked when Wowza tries to figure out which file to play 58 | * @param stream the stream requested 59 | * @param name the name of the file to play 60 | * @param ext the extension of the file 61 | * @param streamQuery the query string from the stream. 62 | * @return the file to play 63 | */ 64 | @Override 65 | public File streamToFileForRead(IMediaStream stream, String name, String ext, String streamQuery) { 66 | logger.trace( 67 | "streamToFileForRead(IMediaStream stream=" + stream + ", String name=" + name + ", String ext=" + ext 68 | + ", String streamQuery=" + streamQuery + ")"); 69 | File streamingFile = getFileToStream(name); 70 | logger.debug( 71 | "streamToFileForRead(IMediaStream stream=" + stream + ", String name=" + name + ", String ext=" + ext 72 | + ", String streamQuery=" + streamQuery + "). Resulting streaming file: '" + streamingFile 73 | .getAbsolutePath() + "'"); 74 | return streamingFile; 75 | } 76 | 77 | /** 78 | * Ignore parts of name after first . and before first : 79 | * @param name 80 | * @return 81 | */ 82 | private String clean(String name) { 83 | if (name.contains(".")){ 84 | name = name.substring(0, name.indexOf(".")); 85 | } 86 | if (name.contains(":")) { 87 | name = name.substring(name.lastIndexOf(':') + 1); 88 | } 89 | 90 | return name; 91 | } 92 | 93 | /** 94 | * This method retrieves the filename, by querying the content resolver to get the 95 | * streaming resource 96 | * @param name the filename 97 | * @return the file to stream 98 | */ 99 | protected File getFileToStream(String name) { 100 | // Extract 101 | name = clean(name); 102 | logger.debug("Looking up '" + name + "'"); 103 | List resources = contentResolver.getContent(name).getResources(); 104 | if (resources != null) { 105 | logger.debug("Found resources, size: '" + resources.size() + "'"); 106 | for (Resource resource : resources) { 107 | if (resource.getType().equals(presentationType)) { 108 | String pathname = resource.getUris().get(0).getPath(); 109 | logger.info("Found '" + pathname + "' for '" + name + "'"); 110 | return new File(pathname); 111 | } 112 | } 113 | } 114 | logger.info("Content not found for: '" + name + "'"); 115 | return FILE_NOT_FOUND_NON_EXISTENT_FILE; 116 | } 117 | 118 | @Override 119 | public File streamToFileForWrite(IMediaStream stream) { 120 | logger.trace("streamToFileForWrite(IMediaStream stream):" + stream); 121 | return defaultMapper.streamToFileForRead(stream); 122 | } 123 | 124 | @Override 125 | public File streamToFileForWrite(IMediaStream stream, String name, String ext, String query) { 126 | logger.trace("streamToFileForWrite(IMediaStream stream, String name, String ext, String query)" + stream); 127 | return defaultMapper.streamToFileForRead(stream, name, ext, query); 128 | } 129 | 130 | } 131 | -------------------------------------------------------------------------------- /wowza-content-resolver-module/src/test/resources/streamingDir/0/e/f/8/0ef8f946-4e90-4c9d-843a-a03504d2ee6c.flv: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kb-dk/wowza-modules/9ae40c763bf703ae994ac75751539e8d90046feb/wowza-content-resolver-module/src/test/resources/streamingDir/0/e/f/8/0ef8f946-4e90-4c9d-843a-a03504d2ee6c.flv -------------------------------------------------------------------------------- /wowza-content-resolver-module/src/test/resources/streamingDir/README.streamingDir: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kb-dk/wowza-modules/9ae40c763bf703ae994ac75751539e8d90046feb/wowza-content-resolver-module/src/test/resources/streamingDir/README.streamingDir -------------------------------------------------------------------------------- /wowza-db-statistics-module/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4.0.0 4 | 5 | 6 | dk.statsbiblioteket.medieplatform 7 | wowza-modules 8 | 4.8-SNAPSHOT 9 | 10 | 11 | wowza-db-statistics-module 12 | 13 | 14 | 15 | dk.statsbiblioteket.medieplatform 16 | wowza-common 17 | 18 | 19 | 20 | dk.statsbiblioteket.medieplatform 21 | wowza-mcm-statistics-module 22 | 23 | 24 | 25 | com.wms 26 | wms-server 27 | provided 28 | 29 | 30 | 31 | com.wms 32 | wms-bootstrap 33 | provided 34 | 35 | 36 | 37 | com.wms 38 | wms-core 39 | provided 40 | 41 | 42 | 43 | com.wms 44 | wms-transcoder 45 | provided 46 | 47 | 48 | 49 | com.wms 50 | wms-rest 51 | provided 52 | 53 | 54 | 55 | com.wms 56 | wms-pushpublish 57 | provided 58 | 59 | 60 | 61 | log4j 62 | log4j 63 | provided 64 | 65 | 66 | 67 | org.bouncycastle 68 | bcprov-jdk15on 69 | provided 70 | 71 | 72 | 73 | commons-lang 74 | commons-lang 75 | provided 76 | 77 | 78 | 79 | org.junit.jupiter 80 | junit-jupiter-engine 81 | test 82 | 83 | 84 | org.mockito 85 | mockito-core 86 | test 87 | 88 | 89 | 90 | org.hsqldb 91 | hsqldb 92 | 1.8.0.10 93 | test 94 | 95 | 96 | 97 | -------------------------------------------------------------------------------- /wowza-db-statistics-module/src/test/java/dk/statsbiblioteket/medieplatform/wowza/plugin/mockobjects/MCMPortalInterfaceStatisticsMock.java: -------------------------------------------------------------------------------- 1 | package dk.statsbiblioteket.medieplatform.wowza.plugin.mockobjects; 2 | 3 | import com.wowza.wms.logging.WMSLogger; 4 | 5 | import dk.statsbiblioteket.medieplatform.wowza.plugin.statistic.logger.mcm.MCMPortalInterfaceStatistics; 6 | 7 | /** 8 | * Mock class for MCM to use in statistics tests. 9 | */ 10 | public class MCMPortalInterfaceStatisticsMock implements MCMPortalInterfaceStatistics { 11 | 12 | private WMSLogger logger; 13 | 14 | private int sessionID = 0; 15 | private int sessionObjectID = 0; 16 | 17 | public String lastSessionID; 18 | public String lastObjectSessionID; 19 | public long lastStartedAt; 20 | public long lastEndedAt; 21 | 22 | public MCMPortalInterfaceStatisticsMock(WMSLogger logger) { 23 | super(); 24 | this.logger = logger; 25 | } 26 | 27 | @Override 28 | public String getStatisticsSession() { 29 | String result = "" + sessionID++; 30 | logger.info("Retrieving session id: " + result); 31 | return result; 32 | } 33 | 34 | @Override 35 | public String getStatisticsObjectSession(String sessionID, 36 | String mcmObjectID) { 37 | String result = sessionID + "-" + sessionObjectID++; 38 | logger.info("Retrieving session object id: " + result); 39 | return result; 40 | } 41 | 42 | @Override 43 | public String logPlayDuration(String sessionID, String objectSessionID, 44 | long startedAt, long endedAt) { 45 | logger.info("logging: [" + sessionID + "-" + sessionObjectID + ": " + startedAt + "; " + endedAt + "]"); 46 | lastSessionID = sessionID; 47 | lastObjectSessionID = objectSessionID; 48 | lastStartedAt = startedAt; 49 | lastEndedAt = endedAt; 50 | 51 | return ""; 52 | } 53 | 54 | } 55 | -------------------------------------------------------------------------------- /wowza-mcm-authorization-module/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4.0.0 4 | 5 | 6 | dk.statsbiblioteket.medieplatform 7 | wowza-modules 8 | 4.8-SNAPSHOT 9 | 10 | 11 | wowza-mcm-authorization-module 12 | 13 | 14 | 15 | 16 | dk.statsbiblioteket.medieplatform 17 | wowza-common 18 | 19 | 20 | 21 | com.wms 22 | wms-server 23 | provided 24 | 25 | 26 | 27 | com.wms 28 | wms-bootstrap 29 | provided 30 | 31 | 32 | 33 | com.wms 34 | wms-core 35 | provided 36 | 37 | 38 | 39 | com.wms 40 | wms-transcoder 41 | provided 42 | 43 | 44 | 45 | com.wms 46 | wms-rest 47 | provided 48 | 49 | 50 | 51 | com.wms 52 | wms-pushpublish 53 | provided 54 | 55 | 56 | 57 | log4j 58 | log4j 59 | provided 60 | 61 | 62 | 63 | org.bouncycastle 64 | bcprov-jdk15on 65 | provided 66 | 67 | 68 | 69 | commons-lang 70 | commons-lang 71 | provided 72 | 73 | 74 | 75 | org.junit.jupiter 76 | junit-jupiter-engine 77 | test 78 | 79 | 80 | org.mockito 81 | mockito-core 82 | test 83 | 84 | 85 | 86 | org.hsqldb 87 | hsqldb 88 | 1.8.0.10 89 | test 90 | 91 | 92 | 93 | 94 | -------------------------------------------------------------------------------- /wowza-mcm-authorization-module/src/main/java/dk/statsbiblioteket/medieplatform/wowza/plugin/authentication/model/MCMOReturnValueWrapper.java: -------------------------------------------------------------------------------- 1 | package dk.statsbiblioteket.medieplatform.wowza.plugin.authentication.model; 2 | 3 | import org.apache.log4j.Logger; 4 | import org.w3c.dom.Document; 5 | import org.w3c.dom.Element; 6 | import org.w3c.dom.NodeList; 7 | import org.xml.sax.SAXException; 8 | 9 | import javax.xml.parsers.DocumentBuilder; 10 | import javax.xml.parsers.DocumentBuilderFactory; 11 | import javax.xml.parsers.ParserConfigurationException; 12 | import java.io.IOException; 13 | import java.io.InputStream; 14 | import java.util.ArrayList; 15 | import java.util.List; 16 | 17 | /** 18 | * Wrapper for a response from MCM. Will update the state of the return value from the response ML document. 19 | */ 20 | public class MCMOReturnValueWrapper { 21 | 22 | protected Logger logger; 23 | protected boolean isSessionValid; 24 | protected String objectID; 25 | protected List filenames; 26 | 27 | public MCMOReturnValueWrapper(Logger logger, InputStream inputStreamFromMCM) throws MCMOutputException { 28 | super(); 29 | this.logger = logger; 30 | extractReturnValuesFromXML(inputStreamFromMCM); 31 | } 32 | 33 | /** 34 | * Get the result from the call. 35 | * Reads XML document from input stream, and parses values using 36 | * {@link #extractMultipleElementsStringContent(Element, String)} 37 | * @param mcmXMLOutputIS Returned XML document. 38 | * @throws MCMOutputException On trouble communicating or parsing. 39 | */ 40 | protected void extractReturnValuesFromXML(InputStream mcmXMLOutputIS) throws MCMOutputException { 41 | try { 42 | Document dom = null; 43 | DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance(); 44 | DocumentBuilder db = dbf.newDocumentBuilder(); 45 | dom = db.parse(mcmXMLOutputIS); 46 | Element docEle = dom.getDocumentElement(); 47 | extractReturnValuesForSession(docEle); 48 | } catch(ParserConfigurationException e) { 49 | throw new MCMOutputException("Could not parse MCM xml output.", e); 50 | } catch(SAXException e) { 51 | throw new MCMOutputException("Could not parse MCM xml output.", e); 52 | } catch(IOException e) { 53 | throw new MCMOutputException("Could not retrieve MCM output.", e); 54 | } 55 | } 56 | 57 | /** 58 | * Get the result from the call. 59 | * If the call is successful, extracts object ID from the element GUID and file name from the element Filename. 60 | * @param docEle Returned XML document. 61 | * @throws MCMOutputException On trouble communicating or parsing. 62 | */ 63 | protected void extractReturnValuesForSession(Element docEle) throws MCMOutputException { 64 | String returnType = docEle.getNodeName(); 65 | if (returnType.equals("ICollection")) { 66 | this.isSessionValid = true; 67 | this.objectID = extractStringContent(docEle, "ObjectID"); 68 | // Extract filename and path from MCM output 69 | this.filenames = extractMultipleElementsStringContent(docEle, "Filename"); 70 | } else if (returnType.equals("Exception")) { 71 | this.isSessionValid = false; 72 | this.objectID = null; 73 | this.filenames = null; 74 | logger.warn("Exception returned from MCM."); 75 | } else { 76 | throw new MCMOutputException("Unexpected return value from MCM. Root element was: " + returnType); 77 | } 78 | } 79 | 80 | /** 81 | * Helper method to extract values from an element in an XML document. 82 | * @param docEle XML document to extract values from. 83 | * @param elementName Name of element to extract value from. 84 | * @return The value for that element. 85 | */ 86 | protected String extractStringContent(Element docEle, String elementName) { 87 | Element folderPathElement; 88 | NodeList nodelist = docEle.getElementsByTagName(elementName); 89 | if(nodelist != null && nodelist.getLength() > 0) { 90 | folderPathElement = (Element)nodelist.item(0); 91 | } else { 92 | return ""; 93 | } 94 | return folderPathElement.getFirstChild().getNodeValue().trim(); 95 | } 96 | 97 | /** 98 | * Helper method to extract multiple values from an element in an XML document. 99 | * @param docEle XML document to extract values from. 100 | * @param elementName Name of element to extract values from. 101 | * @return List of values for that element. 102 | */ 103 | protected List extractMultipleElementsStringContent(Element docEle, String elementName) { 104 | List extractedValues = new ArrayList(); 105 | NodeList nodelist = docEle.getElementsByTagName(elementName); 106 | for (int i=0;i getFilenames() { 123 | return filenames; 124 | } 125 | 126 | public String toString() { 127 | String s = ""; 128 | s += "ReturnValueWrapper. isValidSession=" + isSessionValid 129 | + ", objectID=" + objectID + ", filenames=" + filenames; 130 | return s; 131 | } 132 | 133 | } 134 | -------------------------------------------------------------------------------- /wowza-mcm-authorization-module/src/main/java/dk/statsbiblioteket/medieplatform/wowza/plugin/authentication/model/MCMOutputException.java: -------------------------------------------------------------------------------- 1 | package dk.statsbiblioteket.medieplatform.wowza.plugin.authentication.model; 2 | 3 | /** 4 | * Thrown on trouble reading, parsing or understanding output from MCM. 5 | */ 6 | public class MCMOutputException extends Exception { 7 | 8 | private static final long serialVersionUID = 7225566001480361840L; 9 | 10 | public MCMOutputException(String message) { 11 | super(message); 12 | } 13 | 14 | public MCMOutputException(String message, Throwable cause) { 15 | super(message, cause); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /wowza-mcm-authorization-module/src/main/java/dk/statsbiblioteket/medieplatform/wowza/plugin/authentication/model/SessionAndFilenameValidaterIF.java: -------------------------------------------------------------------------------- 1 | package dk.statsbiblioteket.medieplatform.wowza.plugin.authentication.model; 2 | 3 | import java.io.IOException; 4 | import java.net.MalformedURLException; 5 | 6 | /** 7 | * Interface for checking a session for validity for playing. 8 | */ 9 | public interface SessionAndFilenameValidaterIF { 10 | 11 | /** 12 | * Given the input, validate if the session has the right to play 13 | * the stated file. 14 | * 15 | *
    16 | *
  1. SessionID and ObjectID are used to call validation server
  2. 17 | *
  3. If the validation server knows the session and object, it returns the 18 | * file name with the given ObjectID
  4. 19 | *
  5. If the local filename and the server filename match, access is 20 | * granted
  6. 21 | *
22 | * 23 | * @param sessionID the MCM session id related to the session. This is not the Wowza 24 | * clientID 25 | * @param objectID the object id of the given file to be played. 26 | * @param filename the file to be streamed. 27 | * @return true if the session is allowed to play the file, 28 | * false otherwise. 29 | * @throws MalformedURLException if the URL to the validation server is malformed. 30 | * @throws IOException if something went wrong when connecting to the server. 31 | * @throws MCMOutputException if the output from MCM cannot be read. 32 | */ 33 | public abstract boolean validateRightsToPlayFile(String sessionID, 34 | String objectID, String filename) throws MalformedURLException, 35 | IOException, MCMOutputException; 36 | 37 | } -------------------------------------------------------------------------------- /wowza-mcm-authorization-module/src/test/java/dk/statsbiblioteket/medieplatform/wowza/plugin/authentication/model/MCMOReturnValueWrapperTest.java: -------------------------------------------------------------------------------- 1 | package dk.statsbiblioteket.medieplatform.wowza.plugin.authentication.model; 2 | 3 | import com.wowza.wms.logging.WMSLoggerFactory; 4 | import org.apache.log4j.Logger; 5 | import org.junit.jupiter.api.AfterEach; 6 | import org.junit.jupiter.api.BeforeEach; 7 | import org.junit.jupiter.api.Test; 8 | import static org.junit.jupiter.api.Assertions.*; 9 | 10 | import java.io.FileInputStream; 11 | import java.io.FileNotFoundException; 12 | import java.io.InputStream; 13 | import java.util.List; 14 | 15 | 16 | /** 17 | * Tests for parsing XML results in the return value wrapper. 18 | */ 19 | public class MCMOReturnValueWrapperTest { 20 | 21 | private String filenameOfvalidMCMOutputFull = getClass().getClassLoader().getResource( 22 | "test_data_MCM_output_full.xml").getPath(); 23 | private String filenameOfvalidMCMOutputMultipleFiles = getClass().getClassLoader().getResource( 24 | "test_data_MCM_output_multiple_files.xml").getPath(); 25 | private String filenameOfvalidMCMOutputInvalidSession = getClass().getClassLoader().getResource( 26 | "test_data_MCM_output_invalid_session.xml").getPath(); 27 | private String filenameOfInvalidMCMOutput = getClass().getClassLoader().getResource( 28 | "test_data_invalid_output.xml").getPath(); 29 | 30 | private Logger logger; 31 | 32 | public MCMOReturnValueWrapperTest() { 33 | super(); 34 | this.logger = WMSLoggerFactory.getLogger(this.getClass()); 35 | } 36 | 37 | @BeforeEach 38 | public void setUp() throws Exception { 39 | org.apache.log4j.BasicConfigurator.configure(); 40 | } 41 | 42 | @AfterEach 43 | public void tearDown() throws Exception { 44 | org.apache.log4j.BasicConfigurator.resetConfiguration(); 45 | } 46 | 47 | @Test 48 | public void testExtractOutputFilename() throws FileNotFoundException, MCMOutputException { 49 | InputStream is = getTestDataFileAsInputStream(filenameOfvalidMCMOutputFull); 50 | MCMOReturnValueWrapper returnWrapper = new MCMOReturnValueWrapper(logger, is); 51 | String returnedValue = returnWrapper.getFilenames().get(0); 52 | String expectedValue = "P1_0000_0200_910201_001.mp3"; 53 | assertEquals(expectedValue, returnedValue, "Filename"); 54 | } 55 | 56 | @Test 57 | public void testExtractOutputObjectID() throws FileNotFoundException, MCMOutputException { 58 | InputStream is = getTestDataFileAsInputStream(filenameOfvalidMCMOutputFull); 59 | MCMOReturnValueWrapper returnWrapper = new MCMOReturnValueWrapper(logger, is); 60 | String returnedValue = returnWrapper.getObjectID(); 61 | String expectedValue = "643703"; 62 | assertEquals(expectedValue, returnedValue, "ObjectID"); 63 | } 64 | 65 | @Test 66 | public void testExtractOutputInvalidSessionID() throws FileNotFoundException, MCMOutputException { 67 | InputStream is = getTestDataFileAsInputStream(filenameOfvalidMCMOutputInvalidSession); 68 | MCMOReturnValueWrapper returnWrapper = new MCMOReturnValueWrapper(logger, is); 69 | boolean returnedValue = returnWrapper.isSessionValid(); 70 | boolean expectedValue = false; 71 | assertEquals(expectedValue, returnedValue, "Valid session"); 72 | } 73 | 74 | @Test 75 | public void testExtractOutputBogusXML() throws FileNotFoundException, MCMOutputException { 76 | InputStream is = getTestDataFileAsInputStream(filenameOfInvalidMCMOutput); 77 | assertThrows(MCMOutputException.class, () -> { 78 | new MCMOReturnValueWrapper(logger, is); 79 | }); 80 | 81 | } 82 | 83 | @Test 84 | public void testExtractMultipleFilenames() throws FileNotFoundException, MCMOutputException { 85 | InputStream is = getTestDataFileAsInputStream(filenameOfvalidMCMOutputMultipleFiles); 86 | MCMOReturnValueWrapper returnWrapper = new MCMOReturnValueWrapper(logger, is); 87 | List returnedFilenames = returnWrapper.getFilenames(); 88 | String expectedValue1 = "P2_1800_2000_890121_001.mp3"; 89 | String expectedValue2 = "P2_2000_2200_890121_001.mp3"; 90 | assertTrue(returnedFilenames.contains(expectedValue1), "Filename"); 91 | assertTrue(returnedFilenames.contains(expectedValue2), "Filename"); 92 | } 93 | 94 | private InputStream getTestDataFileAsInputStream(String inputstring) throws FileNotFoundException { 95 | FileInputStream fis; 96 | try { 97 | // If run from ant in command line 98 | fis = new FileInputStream(inputstring); 99 | } catch (FileNotFoundException e) { 100 | // If run from Eclipse 101 | fis = new FileInputStream("trunk/" + inputstring); 102 | } 103 | return fis; 104 | } 105 | } 106 | -------------------------------------------------------------------------------- /wowza-mcm-authorization-module/src/test/java/dk/statsbiblioteket/medieplatform/wowza/plugin/authentication/model/MCMSessionAndFilenameValidaterTest.java: -------------------------------------------------------------------------------- 1 | package dk.statsbiblioteket.medieplatform.wowza.plugin.authentication.model; 2 | 3 | import com.wowza.wms.logging.WMSLogger; 4 | import com.wowza.wms.logging.WMSLoggerFactory; 5 | import org.junit.jupiter.api.AfterEach; 6 | import org.junit.jupiter.api.BeforeEach; 7 | import org.junit.jupiter.api.Test; 8 | import static org.junit.jupiter.api.Assertions.*; 9 | 10 | import java.io.IOException; 11 | import java.util.ArrayList; 12 | import java.util.Arrays; 13 | import java.util.List; 14 | 15 | 16 | /** 17 | * Tests for the validator. 18 | */ 19 | public class MCMSessionAndFilenameValidaterTest { 20 | 21 | private MCMSessionAndFilenameValidater validater; 22 | 23 | public MCMSessionAndFilenameValidaterTest() { 24 | super(); 25 | } 26 | 27 | @BeforeEach 28 | public void setUp() throws Exception { 29 | org.apache.log4j.BasicConfigurator.configure(); 30 | 31 | WMSLogger wmsLogger = WMSLoggerFactory.getLogger(this.getClass()); 32 | validater = new MCMSessionAndFilenameValidater(wmsLogger, "connectionURLString", "validationMethodAtServer"); 33 | } 34 | 35 | @AfterEach 36 | public void tearDown() throws Exception { 37 | org.apache.log4j.BasicConfigurator.resetConfiguration(); 38 | } 39 | 40 | @Test 41 | public void testValidateFilerequestWithMCMResultUnixStylePath() throws MCMOutputException, IOException { 42 | String pathAndFilename = "Kulturarv_MP3/Batch01/Disc02/mp3_128kbps/P1_0000_0200_910201_001"; 43 | List validatingFilenames = Arrays.asList("P1_0000_0200_910201_001.mp3", "anotherfile.mp3"); 44 | 45 | boolean doesValidate = validater.validateFilerequestWithMCMResult(pathAndFilename, validatingFilenames); 46 | 47 | assertTrue(doesValidate); 48 | } 49 | 50 | @Test 51 | public void testValidateFilerequestWithMCMResultWindowsStylePath() throws MCMOutputException, IOException { 52 | String pathAndFilename = "Kulturarv_MP3\\Batch01\\Disc02\\mp3_128kbps\\P1_0000_0200_910201_001"; 53 | List validatingFilenames = Arrays.asList("P1_0000_0200_910201_001.mp3", "anotherfile.mp3"); 54 | 55 | boolean doesValidate = validater.validateFilerequestWithMCMResult(pathAndFilename, validatingFilenames); 56 | 57 | assertTrue(doesValidate); 58 | } 59 | 60 | @Test 61 | public void testValidateFilerequestWithMCMResultNotFound() throws MCMOutputException, IOException { 62 | String pathAndFilename = "Kulturarv_MP3\\Batch01\\Disc02\\mp3_128kbps\\P1_0000_0200_910201_001"; 63 | List validatingFilenames = Arrays.asList("anotherfile.mp3"); 64 | 65 | boolean doesValidate = validater.validateFilerequestWithMCMResult(pathAndFilename, validatingFilenames); 66 | 67 | assertFalse(doesValidate); 68 | } 69 | 70 | @Test 71 | public void testCleanFilename() throws Exception { 72 | assertEquals("test", validater.cleanFilename("/usr/local/test")); 73 | assertEquals("test", validater.cleanFilename("c:\\Documents\\test")); 74 | assertEquals("test", validater.cleanFilename("test.txt")); 75 | assertEquals("test.file", validater.cleanFilename("test.file.txt")); 76 | assertEquals("test", validater.cleanFilename("/usr/local/test.txt")); 77 | assertEquals("test", validater.cleanFilename("c:\\Documents\\test.mp3")); 78 | } 79 | } 80 | -------------------------------------------------------------------------------- /wowza-mcm-authorization-module/src/test/java/dk/statsbiblioteket/medieplatform/wowza/plugin/mockobjects/SessionAndFilenameValidaterMock.java: -------------------------------------------------------------------------------- 1 | package dk.statsbiblioteket.medieplatform.wowza.plugin.mockobjects; 2 | 3 | import dk.statsbiblioteket.medieplatform.wowza.plugin.authentication.model.SessionAndFilenameValidaterIF; 4 | 5 | import java.io.File; 6 | import java.io.IOException; 7 | import java.net.MalformedURLException; 8 | 9 | /** 10 | * Mock for the session and filename validator. 11 | */ 12 | public class SessionAndFilenameValidaterMock implements 13 | SessionAndFilenameValidaterIF { 14 | 15 | private String validSessionID; 16 | private String invalidSessionID; 17 | private String validObjectID; 18 | private String invalidObjectID; 19 | private String validFilename; 20 | private String invalidFilename; 21 | 22 | public SessionAndFilenameValidaterMock() { 23 | this.validSessionID = "5F95E509-FD84-4570-9382-FEC5481E342F"; 24 | this.invalidSessionID = "E32262ED-21A8-46CB-BDA3-FF8D284DAC48"; 25 | this.validObjectID = "976"; 26 | this.invalidObjectID = "977"; 27 | this.validFilename = new File("P3_2000_2200_890325_001.mp3").getAbsolutePath(); 28 | this.invalidFilename = new File("P3_2000_2200_890325_001_invalid.mp3").getAbsolutePath(); 29 | } 30 | 31 | @Override 32 | public boolean validateRightsToPlayFile(String sessionID, String objectID, 33 | String filename) throws MalformedURLException, IOException { 34 | // Validate input: 35 | if (!(objectID.equals(validObjectID) || objectID.equals(invalidObjectID) || 36 | objectID.equals("MalformedURLExceptionTrigger") || objectID.equals("IOExceptionTrigger") || objectID.equals("MCMOutputExceptionTrigger"))) { 37 | throw new IllegalArgumentException("Input not mocked exception"); 38 | } 39 | if (!(sessionID.equals(validSessionID) || sessionID.equals(invalidSessionID))) { 40 | throw new IllegalArgumentException("Input not mocked exception"); 41 | } 42 | if (!(filename.equals(validFilename) || filename.equals(invalidFilename))) { 43 | throw new IllegalArgumentException("Input not mocked exception. Filename: " + filename); 44 | } 45 | // Simulate behavior 46 | if (objectID.equals("MalformedURLExceptionTrigger")) { 47 | throw new MalformedURLException("Test MalformedURLException"); 48 | } 49 | if (objectID.equals("IOExceptionTrigger")) { 50 | throw new IOException("Test IOException"); 51 | } 52 | if (objectID.equals("MCMOutputExceptionTrigger")) { 53 | throw new IOException("Test IOException"); 54 | } 55 | if (sessionID.equals(validSessionID) && objectID.equals(validObjectID) && filename.equals(validFilename)) { 56 | return true; 57 | } else { 58 | return false; 59 | } 60 | } 61 | 62 | } 63 | -------------------------------------------------------------------------------- /wowza-mcm-authorization-module/src/test/resources/test_data_MCM_output_full.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 643703 7 | 8 | \\130.225.231.88\g\DKA\Kulturarv_MP3\Batch01\Disc02\mp3_128kbps\P1_0000_0200_910201_001.mp3 9 | 10 | 11 | http://www.danskkulturarv.dk/PROXY/Preview02/Kulturarv_MP3/Batch01/Disc02/mp3_128kbps/P1_0000_0200_910201_001.mp3 12 | 13 | 14 | rtmp://streaming.chaos.larm-archive.org/chaos_vod/mp3:Kulturarv_MP3/Batch01/Disc02/mp3_128kbps/P1_0000_0200_910201_001.mp3 15 | 16 | MP3 128 kbit CBR 17 | audio/mpeg 18 | 15225 19 | 390996 20 | P1_0000_0200_910201_001.mp3 21 | P1_0000_0200_910201_001.mp3 22 | Kulturarv_MP3\Batch01\Disc02\mp3_128kbps\ 23 | 2010-09-19T18:09:11Z 24 | 2 25 | 7426 26 | 0 27 | 28 | 29 | 2010-09-19T18:09:10Z 30 | Larm.File 31 | 643703 32 | 2010-09-19T18:09:00Z 33 | 37 34 | 8 35 | 36 | -------------------------------------------------------------------------------- /wowza-mcm-authorization-module/src/test/resources/test_data_MCM_output_invalid_session.xml: -------------------------------------------------------------------------------- 1 | 2 | The SessionID is not valid 3 | Geckon.Security.Web.SessionNotAuthenticatedException 4 | 5 | at Geckon.Portal.Web.Service.PortalServiceBase.GetUserInfo(UserInfo userInfo, Products productFlags) in C:\Geckon\Repository\Active\Geckon.Portal\trunk\src\app\Geckon.Portal.Web.Service\PortalServiceBase.cs:line 106 6 | at Geckon.Portal.Web.Service.PortalServiceBase.GetUserInfo(String sessionID, Products productFlags) in C:\Geckon\Repository\Active\Geckon.Portal\trunk\src\app\Geckon.Portal.Web.Service\PortalServiceBase.cs:line 125 7 | at Geckon.Portal.Web.Service.PortalService.Object_Get(String sessionID, Nullable`1 objectID, Nullable`1 objectTypeID, Nullable`1 folderID, Nullable`1 objectCollectionID, Nullable`1 mediaTypeID, Nullable`1 metadataSchemaID, Nullable`1 pageSize, Nullable`1 pageIndex, Nullable`1 includeFiles, Nullable`1 includePhrases, Nullable`1 includeMetadata, Int32[] metadataLanguageIDs, Nullable`1 includePublishSettings, Nullable`1 includePhrasesAndFiles, String metadataFreeTextQuery, Nullable`1 channelID, String[] metadataAliases, String[] metadataAliasConditions, String[] metadataOrderByConditions, Nullable`1 segmentSeparator, String[] metadataXPathFilters, Nullable`1 metadataStandardID, Nullable`1 includeRelations) in C:\Geckon\Repository\Active\Geckon.Portal\trunk\src\app\Geckon.Portal.Web.Service\PortalService.cs:line 144 8 | at SyncInvokeObject_Get(Object , Object[] , Object[] ) 9 | at System.ServiceModel.Dispatcher.SyncMethodInvoker.Invoke(Object instance, Object[] inputs, Object[]& outputs) 10 | at System.ServiceModel.Dispatcher.DispatchOperationRuntime.InvokeBegin(MessageRpc& rpc) 11 | at System.ServiceModel.Dispatcher.ImmutableDispatchRuntime.ProcessMessage5(MessageRpc& rpc) 12 | at System.ServiceModel.Dispatcher.ImmutableDispatchRuntime.ProcessMessage31(MessageRpc& rpc) 13 | at System.ServiceModel.Dispatcher.MessageRpc.Process(Boolean isOperationContextSet) 14 | 15 | -------------------------------------------------------------------------------- /wowza-mcm-authorization-module/src/test/resources/test_data_MCM_output_multiple_files.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 662670 7 | MP3 128 kbit CBR 8 | audio/mpeg 9 | 15225 10 | Kulturarv_MP3\Batch02\Disc05\mp3_128kbps\P2_1800_2000_890121_001.mp3 11 | 12 | 13 | RTMP 14 | 7763 15 | rtmp://streaming.chaos.larm-archive.org/chaos?sessionID=&objectID=&includeFiles=true/mp3:Kulturarv_MP3/Batch02/Disc05/mp3_128kbps/P2_1800_2000_890121_001.mp3 16 | 17 | 18 | 400923 19 | P2_1800_2000_890121_001.mp3 20 | P2_1800_2000_890121_001.mp3 21 | Kulturarv_MP3\Batch02\Disc05\mp3_128kbps\ 22 | 2010-09-19T21:27:32Z 23 | 2 24 | 7426 25 | 0 26 | 7763 27 | 28 | 29 | 662670 30 | MP3 128 kbit CBR 31 | audio/mpeg 32 | 15225 33 | Kulturarv_MP3\Batch02\Disc05\mp3_128kbps\P2_2000_2200_890121_001.mp3 34 | 35 | 36 | RTMP 37 | 7763 38 | rtmp://streaming.chaos.larm-archive.org/chaos?sessionID=&objectID=&includeFiles=true/mp3:Kulturarv_MP3/Batch02/Disc05/mp3_128kbps/P2_2000_2200_890121_001.mp3 39 | 40 | 41 | 400924 42 | P2_2000_2200_890121_001.mp3 43 | P2_2000_2200_890121_001.mp3 44 | Kulturarv_MP3\Batch02\Disc05\mp3_128kbps\ 45 | 2010-09-19T21:27:32Z 46 | 2 47 | 7426 48 | 0 49 | 7763 50 | 51 | 52 | 2011-02-08T15:53:57Z 53 | Larm.Program 54 | aa50b1c9-7bba-4408-b8d1-8b336126772c 55 | 662670 56 | 2010-09-19T21:28:00Z 57 | 37 58 | 8 59 | 60 | 61 | -------------------------------------------------------------------------------- /wowza-mcm-authorization-module/src/test/resources/test_data_invalid_output.xml: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /wowza-mcm-statistics-module/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4.0.0 4 | 5 | 6 | dk.statsbiblioteket.medieplatform 7 | wowza-modules 8 | 4.8-SNAPSHOT 9 | 10 | 11 | wowza-mcm-statistics-module 12 | 13 | 14 | 15 | 16 | dk.statsbiblioteket.medieplatform 17 | wowza-common 18 | 19 | 20 | 21 | com.wms 22 | wms-server 23 | provided 24 | 25 | 26 | 27 | com.wms 28 | wms-core 29 | provided 30 | 31 | 32 | 33 | com.wms 34 | wms-transcoder 35 | provided 36 | 37 | 38 | 39 | com.wms 40 | wms-rest 41 | provided 42 | 43 | 44 | 45 | log4j 46 | log4j 47 | provided 48 | 49 | 50 | 51 | org.bouncycastle 52 | bcprov-jdk15on 53 | provided 54 | 55 | 56 | 57 | commons-lang 58 | commons-lang 59 | provided 60 | 61 | 62 | 63 | org.junit.jupiter 64 | junit-jupiter-engine 65 | test 66 | 67 | 68 | 69 | org.hsqldb 70 | hsqldb 71 | 1.8.0.10 72 | test 73 | 74 | 75 | 76 | -------------------------------------------------------------------------------- /wowza-mcm-statistics-module/src/main/java/dk/statsbiblioteket/medieplatform/wowza/plugin/statistic/logger/SessionIDPair.java: -------------------------------------------------------------------------------- 1 | package dk.statsbiblioteket.medieplatform.wowza.plugin.statistic.logger; 2 | 3 | /** 4 | * Pair of SessionID and ObjectSessionID used for generating a log entry. 5 | */ 6 | public class SessionIDPair { 7 | 8 | // ID pair for MCM statistics logging 9 | public String sessionID; 10 | public String objectSessionID; 11 | 12 | public SessionIDPair(String sessionID, String objectSessionID) { 13 | this.sessionID = sessionID; 14 | this.objectSessionID = objectSessionID; 15 | } 16 | 17 | public String getSessionID() { 18 | return sessionID; 19 | } 20 | 21 | public String getObjectSessionID() { 22 | return objectSessionID; 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /wowza-mcm-statistics-module/src/main/java/dk/statsbiblioteket/medieplatform/wowza/plugin/statistic/logger/StreamingEventLoggerIF.java: -------------------------------------------------------------------------------- 1 | package dk.statsbiblioteket.medieplatform.wowza.plugin.statistic.logger; 2 | 3 | /** 4 | * Interface for logging streaming events. 5 | */ 6 | public interface StreamingEventLoggerIF { 7 | 8 | /** 9 | * Get the session ID used for logging 10 | * @param mcmObjectID Given an MCM object ID, return the session ID pair used for generating a log entry. 11 | * @return The session ID pair. 12 | */ 13 | public abstract SessionIDPair getStreamingLogSessionID(String mcmObjectID); 14 | 15 | /** 16 | * Log an event. 17 | * @param logEntry The event to log. 18 | */ 19 | public abstract void logEvent(StreamingStatLogEntry logEntry); 20 | 21 | /** 22 | * Get the latest log event. 23 | * @return The latest log event. 24 | */ 25 | public abstract StreamingStatLogEntry getLogEntryLatest(); 26 | 27 | } -------------------------------------------------------------------------------- /wowza-mcm-statistics-module/src/main/java/dk/statsbiblioteket/medieplatform/wowza/plugin/statistic/logger/mcm/MCMPortalInterfaceStatistics.java: -------------------------------------------------------------------------------- 1 | package dk.statsbiblioteket.medieplatform.wowza.plugin.statistic.logger.mcm; 2 | 3 | /** Interface for logging events to MCM, and reading them. 4 | * @deprecated */ 5 | public interface MCMPortalInterfaceStatistics { 6 | 7 | public abstract String getStatisticsSession(); 8 | 9 | public abstract String getStatisticsObjectSession(String sessionID, 10 | String mcmObjectID); 11 | 12 | public abstract String logPlayDuration(String sessionID, 13 | String objectSessionID, long startedAt, long endedAt); 14 | 15 | } -------------------------------------------------------------------------------- /wowza-mcm-statistics-module/src/main/java/dk/statsbiblioteket/medieplatform/wowza/plugin/statistic/logger/mcm/StreamingMCMEventLogger.java: -------------------------------------------------------------------------------- 1 | package dk.statsbiblioteket.medieplatform.wowza.plugin.statistic.logger.mcm; 2 | 3 | import com.wowza.wms.logging.WMSLogger; 4 | 5 | import dk.statsbiblioteket.medieplatform.wowza.plugin.statistic.logger.SessionIDPair; 6 | import dk.statsbiblioteket.medieplatform.wowza.plugin.statistic.logger.StreamingEventLoggerIF; 7 | import dk.statsbiblioteket.medieplatform.wowza.plugin.statistic.logger.StreamingStatLogEntry; 8 | import dk.statsbiblioteket.medieplatform.wowza.plugin.statistic.logger.StreamingStatLogEntry.Event; 9 | 10 | import java.util.List; 11 | 12 | /** 13 | * Event logger that logs to MCM. 14 | * @deprecated 15 | */ 16 | public class StreamingMCMEventLogger implements StreamingEventLoggerIF { 17 | 18 | private final WMSLogger logger; 19 | 20 | private static StreamingMCMEventLogger instance = null; 21 | 22 | /** 23 | * Reads db connection information from property file and creates connection 24 | * 25 | * 26 | * @param logger The Wowza logger. 27 | */ 28 | private StreamingMCMEventLogger(WMSLogger logger) { 29 | this.logger = logger; 30 | this.logger.info("Statistics logger " + this.getClass().getName() + " has been created."); 31 | } 32 | 33 | /** 34 | * Creates the singleton objects. Is robust for multiple concurrent requests for create. 35 | * Only the first request for create, actually creates the object. 36 | * @param logger The Wowza logger. 37 | */ 38 | public static synchronized void createInstance(WMSLogger logger) { 39 | if ((logger == null)) { 40 | throw new IllegalArgumentException( 41 | "A parameter is null. " + "logger=" + logger); 42 | } 43 | if (instance == null) { 44 | instance = new StreamingMCMEventLogger(logger); 45 | } 46 | } 47 | 48 | public static synchronized StreamingMCMEventLogger getInstance() { 49 | return instance; 50 | } 51 | 52 | @Override 53 | public SessionIDPair getStreamingLogSessionID(String mcmObjectID) { 54 | String sessionID = MCMPortalInterfaceStatisticsImpl.getInstance().getStatisticsSession(); 55 | String objectSessionID = MCMPortalInterfaceStatisticsImpl.getInstance() 56 | .getStatisticsObjectSession(sessionID, mcmObjectID); 57 | return new SessionIDPair(sessionID, objectSessionID); 58 | } 59 | 60 | @Override 61 | public void logEvent(StreamingStatLogEntry logEntry) { 62 | if (Event.PLAY.equals(logEntry.getEvent()) || Event.PAUSE.equals(logEntry.getEvent()) 63 | || Event.REWIND.equals(logEntry.getEvent()) || Event.STOP.equals(logEntry.getEvent())) { 64 | logger.info("Streaming statistics logging line: " + logEntry); 65 | logEventInMCM(logEntry); 66 | } 67 | } 68 | 69 | private synchronized void logEventInMCM(StreamingStatLogEntry logEntry) { 70 | MCMPortalInterfaceStatisticsImpl.getInstance() 71 | .logPlayDuration(logEntry.getMcmSessionID(), logEntry.getMcmObjectSessionID(), logEntry.getStartedAt(), 72 | logEntry.getEndedAt()); 73 | } 74 | 75 | @Override 76 | public StreamingStatLogEntry getLogEntryLatest() { 77 | throw new UnsupportedOperationException("MCM logger does not support queries"); 78 | } 79 | 80 | public List getLogEntryLatest(int numberOfEntries) { 81 | throw new UnsupportedOperationException("MCM logger does not support queries"); 82 | } 83 | } 84 | -------------------------------------------------------------------------------- /wowza-mcm3-authorization-module/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4.0.0 4 | 5 | 6 | dk.statsbiblioteket.medieplatform 7 | wowza-modules 8 | 4.8-SNAPSHOT 9 | 10 | 11 | wowza-mcm3-authorization-module 12 | 13 | 14 | 15 | dk.statsbiblioteket.medieplatform 16 | wowza-common 17 | 18 | 19 | 20 | dk.statsbiblioteket.medieplatform 21 | wowza-mcm-authorization-module 22 | 23 | 24 | 25 | com.wms 26 | wms-server 27 | provided 28 | 29 | 30 | 31 | com.wms 32 | wms-bootstrap 33 | provided 34 | 35 | 36 | 37 | com.wms 38 | wms-core 39 | provided 40 | 41 | 42 | 43 | com.wms 44 | wms-transcoder 45 | provided 46 | 47 | 48 | 49 | com.wms 50 | wms-rest 51 | provided 52 | 53 | 54 | 55 | com.wms 56 | wms-pushpublish 57 | provided 58 | 59 | 60 | 61 | log4j 62 | log4j 63 | provided 64 | 65 | 66 | 67 | org.bouncycastle 68 | bcprov-jdk15on 69 | provided 70 | 71 | 72 | 73 | commons-lang 74 | commons-lang 75 | provided 76 | 77 | 78 | 79 | org.junit.jupiter 80 | junit-jupiter-engine 81 | test 82 | 83 | 84 | 85 | org.hsqldb 86 | hsqldb 87 | 1.8.0.10 88 | test 89 | 90 | 91 | 92 | -------------------------------------------------------------------------------- /wowza-mcm3-authorization-module/src/main/java/dk/statsbiblioteket/medieplatform/wowza/plugin/authentication/MCM3OReturnValueWrapper.java: -------------------------------------------------------------------------------- 1 | package dk.statsbiblioteket.medieplatform.wowza.plugin.authentication; 2 | 3 | import org.apache.log4j.Logger; 4 | import org.w3c.dom.Element; 5 | import org.w3c.dom.NodeList; 6 | 7 | import dk.statsbiblioteket.medieplatform.wowza.plugin.authentication.model.MCMOReturnValueWrapper; 8 | import dk.statsbiblioteket.medieplatform.wowza.plugin.authentication.model.MCMOutputException; 9 | 10 | import java.io.InputStream; 11 | 12 | /** 13 | * Wrapper for a response from MCM3. Will update the state of the return value from the response ML document. 14 | */ 15 | public class MCM3OReturnValueWrapper extends MCMOReturnValueWrapper { 16 | public MCM3OReturnValueWrapper(Logger logger, InputStream inputStreamFromMCM) throws MCMOutputException { 17 | super(logger, inputStreamFromMCM); 18 | } 19 | 20 | /** 21 | * Get the result from the call. 22 | * If the call is successful, extracts object ID from the element GUID and file name from the element Filename. 23 | * @param docEle Returned XML document. 24 | * @throws MCMOutputException On trouble communicating or parsing. 25 | */ 26 | @Override 27 | protected void extractReturnValuesForSession(Element docEle) throws MCMOutputException { 28 | String returnType = docEle.getNodeName(); 29 | if (returnType.equals("PortalResult")) { 30 | NodeList error = docEle.getElementsByTagName("Error"); 31 | if (error.getLength() == 0) { 32 | this.isSessionValid = true; 33 | this.objectID = extractStringContent(docEle, "ObjectGuid"); 34 | // Extract filename and path from MCM output 35 | this.filenames = extractMultipleElementsStringContent(docEle, "Filename"); 36 | } else { 37 | this.isSessionValid = false; 38 | this.objectID = null; 39 | this.filenames = null; 40 | logger.warn("Error returned from MCM."); 41 | } 42 | } else { 43 | throw new MCMOutputException("Unexpected return value from MCM. Root element was: " + returnType); 44 | } 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /wowza-mcm3-authorization-module/src/main/java/dk/statsbiblioteket/medieplatform/wowza/plugin/authentication/MCM3SessionAndFilenameValidater.java: -------------------------------------------------------------------------------- 1 | package dk.statsbiblioteket.medieplatform.wowza.plugin.authentication; 2 | 3 | import com.wowza.wms.application.IApplicationInstance; 4 | import com.wowza.wms.logging.WMSLogger; 5 | 6 | import dk.statsbiblioteket.medieplatform.wowza.plugin.authentication.model.MCMOReturnValueWrapper; 7 | import dk.statsbiblioteket.medieplatform.wowza.plugin.authentication.model.MCMOutputException; 8 | import dk.statsbiblioteket.medieplatform.wowza.plugin.authentication.model.MCMSessionAndFilenameValidater; 9 | import dk.statsbiblioteket.medieplatform.wowza.plugin.utilities.StringAndTextUtil; 10 | 11 | import java.io.FileNotFoundException; 12 | import java.io.IOException; 13 | import java.io.InputStream; 14 | import java.net.MalformedURLException; 15 | import java.net.URL; 16 | 17 | /** 18 | * Call MCM to see if session is valid and lookup object from the GUID. 19 | */ 20 | public class MCM3SessionAndFilenameValidater extends MCMSessionAndFilenameValidater { 21 | /** 22 | * Reads server connection configuration from property-file. Property file 23 | * is expected to be at "<VHost_HOME>/<propertyFilePath>" 24 | * 25 | * Example of content in property file could be: 26 | * 27 | * GeneralMCM3ServerURL=api.test.chaos-systems.com/ 28 | * ValidationMCM3ValidationMethod=Object/Get 29 | * 30 | * @param logger the logger 31 | * @param appInstance ignored 32 | * @param connectionURLString chaos media content manager service url 33 | * @param validationMethodAtServer name of the validate method in the chaos media content manager service 34 | * @throws FileNotFoundException if property file is not found 35 | * @throws IOException if reading process failed 36 | */ 37 | public MCM3SessionAndFilenameValidater(WMSLogger logger, IApplicationInstance appInstance, 38 | String connectionURLString, String validationMethodAtServer) 39 | throws FileNotFoundException, IOException { 40 | super(); 41 | this.logger = logger; 42 | this.connectionURLString = connectionURLString; 43 | this.validationMethodAtServer = validationMethodAtServer; 44 | } 45 | 46 | public MCM3SessionAndFilenameValidater(WMSLogger logger, String connectionURLString, 47 | String validationMethodAtServer) { 48 | super(logger, connectionURLString, validationMethodAtServer); 49 | } 50 | 51 | /** 52 | * Get session validation information from MCM3. 53 | * @param sessionID MCM3 Session ID 54 | * @param objectID MCM3 Object GUID 55 | * @return Object containing information about session validity and file names for GUID. 56 | * @throws IOException On trouble connection to MCM3 57 | * @throws MalformedURLException On bad URL connecting to MCM3 58 | * @throws MCMOutputException On trouble reading MCM3 output. 59 | */ 60 | @Override 61 | protected MCMOReturnValueWrapper getInputFromMCM(String sessionID, String objectID) 62 | throws IOException, MalformedURLException, MCMOutputException { 63 | String urlStringToMCM = connectionURLString + "/" + validationMethodAtServer + "?" + "sessionGUID=" + sessionID 64 | + "&" + "objectGuids=" + objectID + "&" + "includeMetadata=true" + "&" + "includeFiles=true"; 65 | InputStream in = null; 66 | try { 67 | if (logger.isDebugEnabled()) { 68 | logger.debug("MCM URL:" + urlStringToMCM); 69 | InputStream inDebug = new URL(urlStringToMCM).openConnection().getInputStream(); 70 | logger.debug("Returned from MCM: " + StringAndTextUtil.convertStreamToString(inDebug)); 71 | } 72 | in = new URL(urlStringToMCM).openConnection().getInputStream(); 73 | return new MCM3OReturnValueWrapper(logger, in); 74 | } finally { 75 | if (in != null) { 76 | in.close(); 77 | } 78 | } 79 | } 80 | } 81 | -------------------------------------------------------------------------------- /wowza-mcm3-authorization-module/src/test/java/dk/statsbiblioteket/medieplatform/wowza/plugin/authentication/model/MCM3OReturnValueWrapperTest.java: -------------------------------------------------------------------------------- 1 | package dk.statsbiblioteket.medieplatform.wowza.plugin.authentication.model; 2 | 3 | import java.io.FileInputStream; 4 | import java.io.FileNotFoundException; 5 | import java.io.InputStream; 6 | import java.util.List; 7 | import com.wowza.wms.logging.WMSLoggerFactory; 8 | import dk.statsbiblioteket.medieplatform.wowza.plugin.authentication.MCM3OReturnValueWrapper; 9 | 10 | import org.apache.log4j.Logger; 11 | import org.junit.jupiter.api.AfterEach; 12 | import org.junit.jupiter.api.BeforeEach; 13 | import org.junit.jupiter.api.Test; 14 | import static org.junit.jupiter.api.Assertions.*; 15 | 16 | /** Test return value parsing from MCM3. */ 17 | public class MCM3OReturnValueWrapperTest { 18 | 19 | private String filenameOfvalidMCMOutputFull = getClass().getClassLoader().getResource( 20 | "test_data_MCM3_output_full.xml").getPath(); 21 | private String filenameOfvalidMCMOutputInvalidSession = getClass().getClassLoader().getResource( 22 | "test_data_MCM3_output_invalid_session.xml").getPath(); 23 | private String filenameOfInvalidMCMOutput = getClass().getClassLoader().getResource( 24 | "test_data_invalid_output.xml").getPath(); 25 | 26 | private Logger logger; 27 | 28 | public MCM3OReturnValueWrapperTest() { 29 | super(); 30 | this.logger = WMSLoggerFactory.getLogger(this.getClass()); 31 | } 32 | 33 | @BeforeEach 34 | public void setUp() throws Exception { 35 | org.apache.log4j.BasicConfigurator.configure(); 36 | } 37 | 38 | @AfterEach 39 | public void tearDown() throws Exception { 40 | org.apache.log4j.BasicConfigurator.resetConfiguration(); 41 | } 42 | 43 | @Test 44 | public void testExtractOutputFilename() throws FileNotFoundException, MCMOutputException { 45 | InputStream is = getTestDataFileAsInputStream(filenameOfvalidMCMOutputFull); 46 | MCM3OReturnValueWrapper returnWrapper = new MCM3OReturnValueWrapper(logger, is); 47 | String returnedValue = returnWrapper.getFilenames().get(0); 48 | String expectedValue = "P1_0000_000850_00000000_2023_Tysk propaganda-udsendelse - Reportage fra østfronten.mp3"; 49 | assertEquals(expectedValue, returnedValue, "Filename"); 50 | } 51 | 52 | @Test 53 | public void testExtractOutputObjectID() throws FileNotFoundException, MCMOutputException { 54 | InputStream is = getTestDataFileAsInputStream(filenameOfvalidMCMOutputFull); 55 | MCM3OReturnValueWrapper returnWrapper = new MCM3OReturnValueWrapper(logger, is); 56 | String returnedValue = returnWrapper.getObjectID(); 57 | String expectedValue = "84802737-4910-d941-a7f0-14e4bdf1bc4d"; 58 | assertEquals(expectedValue, returnedValue, "ObjectID"); 59 | } 60 | 61 | @Test 62 | public void testExtractOutputInvalidSessionID() throws FileNotFoundException, MCMOutputException { 63 | InputStream is = getTestDataFileAsInputStream(filenameOfvalidMCMOutputInvalidSession); 64 | MCM3OReturnValueWrapper returnWrapper = new MCM3OReturnValueWrapper(logger, is); 65 | boolean returnedValue = returnWrapper.isSessionValid(); 66 | boolean expectedValue = false; 67 | assertEquals(expectedValue, returnedValue, "Valid session"); 68 | } 69 | 70 | @Test 71 | public void testExtractOutputBogusXML() throws FileNotFoundException, MCMOutputException { 72 | InputStream is = getTestDataFileAsInputStream(filenameOfInvalidMCMOutput); 73 | assertThrows(MCMOutputException.class, () -> { 74 | new MCM3OReturnValueWrapper(logger, is); 75 | }); 76 | 77 | } 78 | 79 | @Test 80 | public void testExtractMultipleFilenames() throws FileNotFoundException, MCMOutputException { 81 | InputStream is = getTestDataFileAsInputStream(filenameOfvalidMCMOutputFull); 82 | MCM3OReturnValueWrapper returnWrapper = new MCM3OReturnValueWrapper(logger, is); 83 | List returnedFilenames = returnWrapper.getFilenames(); 84 | String expectedValue1 = "P1_0000_000850_00000000_2023_Tysk propaganda-udsendelse - Reportage fra østfronten.mp3"; 85 | String expectedValue2 = "P1_logo.png"; 86 | assertTrue(returnedFilenames.contains(expectedValue1), "Filename"); 87 | assertTrue(returnedFilenames.contains(expectedValue2), "Filename"); 88 | } 89 | 90 | private InputStream getTestDataFileAsInputStream(String inputstring) throws FileNotFoundException { 91 | FileInputStream fis; 92 | try { 93 | // If run from ant in command line 94 | fis = new FileInputStream(inputstring); 95 | } catch (FileNotFoundException e) { 96 | // If run from Eclipse 97 | fis = new FileInputStream("trunk/" + inputstring); 98 | } 99 | return fis; 100 | } 101 | } 102 | -------------------------------------------------------------------------------- /wowza-mcm3-authorization-module/src/test/java/dk/statsbiblioteket/medieplatform/wowza/plugin/authentication/model/MCM3SessionAndFilenameValidaterTest.java: -------------------------------------------------------------------------------- 1 | package dk.statsbiblioteket.medieplatform.wowza.plugin.authentication.model; 2 | 3 | import java.io.IOException; 4 | import java.util.ArrayList; 5 | import java.util.List; 6 | import com.wowza.wms.logging.WMSLogger; 7 | import com.wowza.wms.logging.WMSLoggerFactory; 8 | import dk.statsbiblioteket.medieplatform.wowza.plugin.authentication.MCM3SessionAndFilenameValidater; 9 | 10 | import org.apache.log4j.Logger; 11 | 12 | import org.junit.jupiter.api.AfterEach; 13 | import org.junit.jupiter.api.BeforeEach; 14 | import org.junit.jupiter.api.Test; 15 | import static org.junit.jupiter.api.Assertions.*; 16 | 17 | /** Test MCM3 authorization validator */ 18 | public class MCM3SessionAndFilenameValidaterTest { 19 | 20 | private Logger logger; 21 | 22 | public MCM3SessionAndFilenameValidaterTest() { 23 | super(); 24 | this.logger = WMSLoggerFactory.getLogger(this.getClass()); 25 | } 26 | 27 | @BeforeEach 28 | public void setUp() throws Exception { 29 | org.apache.log4j.BasicConfigurator.configure(); 30 | } 31 | 32 | @AfterEach 33 | public void tearDown() throws Exception { 34 | org.apache.log4j.BasicConfigurator.resetConfiguration(); 35 | } 36 | 37 | @Test 38 | public void testValidateFilerequestWithMCMResultUnixStylePath() throws MCMOutputException, IOException { 39 | WMSLogger wmsLogger = WMSLoggerFactory.getLogger(this.getClass()); 40 | String pathAndFilename = "Kulturarv_MP3/Batch01/Disc02/mp3_128kbps/P1_0000_0200_910201_001.mp3"; 41 | List validatingFilenames = new ArrayList(); 42 | validatingFilenames.add("P1_0000_0200_910201_001.mp3"); 43 | MCM3SessionAndFilenameValidater validater = new MCM3SessionAndFilenameValidater(wmsLogger, "connectionURLString", "validationMethodAtServer"); 44 | boolean doesValidate = validater.validateFilerequestWithMCMResult(pathAndFilename, validatingFilenames); 45 | 46 | assertEquals(true, doesValidate, "Filename validation:"); 47 | } 48 | 49 | @Test 50 | public void testValidateFilerequestWithMCMResultWindowsStylePath() throws MCMOutputException, IOException { 51 | WMSLogger wmsLogger = WMSLoggerFactory.getLogger(this.getClass()); 52 | String pathAndFilename = "Kulturarv_MP3\\Batch01\\Disc02\\mp3_128kbps\\P1_0000_0200_910201_001.mp3"; 53 | List validatingFilenames = new ArrayList(); 54 | validatingFilenames.add("P1_0000_0200_910201_001.mp3"); 55 | MCM3SessionAndFilenameValidater validater = new MCM3SessionAndFilenameValidater(wmsLogger, "connectionURLString", "validationMethodAtServer"); 56 | boolean doesValidate = validater.validateFilerequestWithMCMResult(pathAndFilename, validatingFilenames); 57 | assertEquals(true, doesValidate, "Filename validation:"); 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /wowza-mcm3-authorization-module/src/test/resources/test_data_MCM3_output_full.xml: -------------------------------------------------------------------------------- 1 | 84802737-4910-d941-a7f0-14e4bdf1bc4d2428-02-2013 00:28:1015d1f40a-12c5-45ae-8438-64ffe80decf7da00000000-0000-0000-0000-0000df82000085a276ff-20e1-9c4b-b831-7d52ce8f495c<Larm.Program><PublicationDateTime>0101-01-01T00:00:00</PublicationDateTime><PublicationEndDateTime>0101-01-01T00:08:50</PublicationEndDateTime><PublicationChannel>DR P1</PublicationChannel><Title>Tysk propaganda-udsendelse - Reportage fra østfronten</Title><Abstract /><Description /><Publisher /><Subjects /><Contributors /><Creators /><Locations /><Identifiers><DR.ProductionNumber /><DR.ArchiveNumber>2023</DR.ArchiveNumber><SB.DomsID /></Identifiers></Larm.Program>28-02-2013 00:28:102e42e7d3-6a3e-4bb5-ae0e-fbc822344bd3da00000000-0000-0000-0000-0000dd82000085a276ff-20e1-9c4b-b831-7d52ce8f495c<Larm.FileInfos><Larm.FileInfo><StartOffSetMS>0</StartOffSetMS><EndOffSetMS>0</EndOffSetMS><FileName>P1_0000_000850_00000000_2023_Tysk propaganda-udsendelse - Reportage fra østfronten.mp3</FileName><Index>0</Index></Larm.FileInfo></Larm.FileInfos>28-02-2013 00:28:11701560ec-cebf-4b1f-a58d-3cc13377b0d6da419ed517-fb13-9a46-a138-bb691f13f2ba85a276ff-20e1-9c4b-b831-7d52ce8f495c<Larm.Metadata><Title /><Description /><Genre /><Subjects /><Tags /><Note /><RelatedObjects /><Contributors /></Larm.Metadata>28-02-2013 00:28:1113391338184802737-4910-d941-a7f0-14e4bdf1bc4d1P127-02-2013 23:50:541885861184802737-4910-d941-a7f0-14e4bdf1bc4d2radioTransmissions11-03-2014 13:10:491905861184802737-4910-d941-a7f0-14e4bdf1bc4d2radioControll11-03-2014 13:24:0584802737-4910-d941-a7f0-14e4bdf1bc4d53caf17d-8c05-4de5-be31-08e19ea94080162464Part of84802737-4910-d941-a7f0-14e4bdf1bc4d657bc99c-1ee2-4c42-90e1-340906a67acb162464Part of3606432P1_0000_000850_00000000_2023_Tysk propaganda-udsendelse - Reportage fra østfronten.mp3P1_0000_000850_00000000_2023_Tysk propaganda-udsendelse - Reportage fra østfronten.mp3RTMP Streamingrtmp://130.225.250.44:1935/chaos_non/mp3:/Kulturarv_MP3/DRArchive/Allans/P1/P1_0000_000850_00000000_2023_Tysk propaganda-udsendelse - Reportage fra østfronten.mp349LARMAudio3606433P1_logo.pngP1_logo.pngHTTP Downloadhttp://s3-eu-west-1.amazonaws.com/mcm/LarmLogos/P1_logo.png50ThumbnailImage00000000-0000-0000-0000-00000700000084802737-4910-d941-a7f0-14e4bdf1bc4d03-11-2013 09:47:1806-11-2013 09:47:20 -------------------------------------------------------------------------------- /wowza-mcm3-authorization-module/src/test/resources/test_data_MCM3_output_invalid_session.xml: -------------------------------------------------------------------------------- 1 | No folders with access -------------------------------------------------------------------------------- /wowza-mcm3-authorization-module/src/test/resources/test_data_invalid_output.xml: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /wowza-mediestream-vhost/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4.0.0 4 | 5 | 6 | dk.statsbiblioteket.medieplatform 7 | wowza-modules 8 | 4.8-SNAPSHOT 9 | 10 | 11 | wowza-mediestream-vhost 12 | pom 13 | 14 | 15 | 16 | 17 | 18 | maven-assembly-plugin 19 | 2.2.2 20 | 21 | 22 | make-assembly 23 | 24 | 25 | src/main/assembly/assembly.xml 26 | 27 | gnu 28 | 29 | 30 | package 31 | 32 | 33 | single 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | dk.statsbiblioteket.medieplatform 45 | wowza-statistics-module 46 | 47 | 48 | 49 | dk.statsbiblioteket.medieplatform 50 | wowza-ticket-checker-module 51 | 52 | 53 | 54 | dk.statsbiblioteket.medieplatform 55 | wowza-content-resolver-module 56 | 57 | 58 | 59 | com.wms 60 | wms-plugin-collection 61 | 62 | 63 | 64 | -------------------------------------------------------------------------------- /wowza-mediestream-vhost/src/main/assembly/assembly.xml: -------------------------------------------------------------------------------- 1 | 2 | bundle 3 | 4 | 5 | tar.gz 6 | 7 | 8 | 9 | 10 | applications/lib 11 | 0775 12 | true 13 | runtime 14 | 15 | 16 | 17 | 18 | 19 | applications/mediestream 20 | src/main/assembly 21 | 0775 22 | 23 | 24 | * 25 | 26 | 27 | 28 | applications/mediestreamapple 29 | src/main/assembly 30 | 0775 31 | 32 | 33 | * 34 | 35 | 36 | 37 | 46 | 47 | streamingContent 48 | src/main/assembly 49 | 0775 50 | 51 | 52 | * 53 | 54 | 55 | 56 | 65 | 66 | conf 67 | src/main/config/wowza_vhost_mediestream/conf 68 | 69 | 70 | mediestream_preview 71 | mediestream_preview/* 72 | 73 | 0775 74 | 75 | 76 | bin 77 | src/main/scripts 78 | 0775 79 | 0755 80 | 81 | 82 | 83 | -------------------------------------------------------------------------------- /wowza-mediestream-vhost/src/main/config/wowza_vhost_mediestream/conf/MediaCache.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | ${com.wowza.wms.TuningAuto} 7 | 8 | 9 | ${com.wowza.wms.TuningAuto} 10 | 11 | ${com.wowza.wms.TuningAuto} 12 | ${com.wowza.wms.TuningAuto} 13 | 10000 14 | 15 | true 16 | true 17 | false 18 | false 19 | true 20 | false 21 | 22 | 23 | 24 | 25 | default 26 | Default Store 27 | 28 | ${com.wowza.wms.context.ServerConfigHome}/mediacache 29 | 10G 30 | 24 31 | 24 32 | 1000 33 | 16M 34 | 64M 35 | 100 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | dvrorigin 46 | HTTP 47 | Default DVR source 48 | http:// 49 | dvrorigin/ 50 | com.wowza.wms.mediacache.impl.MediaCacheItemHTTPImpl 51 | 52 | 262144 53 | 1200000 54 | 600000 55 | true 56 | 50 57 | 58 | 59 | httpReadTimeout 60 | 3000 61 | Integer 62 | 63 | 64 | 65 | 66 | 67 | 68 | -------------------------------------------------------------------------------- /wowza-mediestream-vhost/src/main/config/wowza_vhost_mediestream/conf/StartupStreams.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /wowza-mediestream-vhost/src/main/config/wowza_vhost_mediestream/conf/Tune.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 12 | ${com.wowza.wms.TuningHeapSizeDevelopment} 13 | 14 | 22 | ${com.wowza.wms.TuningGarbageCollectorG1Default} 23 | 24 | 30 | 31 | -server 32 | -Djava.net.preferIPv4Stack=true 33 | 34 | 35 | 36 | 37 | 38 | 39 | -------------------------------------------------------------------------------- /wowza-mediestream-vhost/src/main/config/wowza_vhost_mediestream/conf/admin.password: -------------------------------------------------------------------------------- 1 | # Admin password file (format [username][space][password][space][group]) 2 | #username password group|group 3 | -------------------------------------------------------------------------------- /wowza-mediestream-vhost/src/main/config/wowza_vhost_mediestream/conf/clientaccesspolicy.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /wowza-mediestream-vhost/src/main/config/wowza_vhost_mediestream/conf/crossdomain.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /wowza-mediestream-vhost/src/main/config/wowza_vhost_mediestream/conf/mediestream/wowza-modules.properties: -------------------------------------------------------------------------------- 1 | # 2 | # Property file for the Wowza Ticket Checker 3 | # 4 | 5 | # comma seperated list (no spaces) with the prefixes for each contentResolver 6 | # defined in the configurations in this property file 7 | contentResolverNames=doms,kuana,kuanaradio 8 | 9 | # Absolute path 10 | streamingStatisticsLogFolder=/home/wowza/logs 11 | 12 | # Number of characters to use for splitting content into directories. Example: if this is 2, the file 13 | # "hello.txt" will be in the path "h/e/hello.txt 14 | doms.characterDirs=4 15 | doms.characterDirsWidth=1 16 | # 17 | doms.subdirectory=doms 18 | # Pattern used for turning the content id into a file name. %s is replaced with the content id. 19 | doms.filenameRegexPattern=%s\\.(mp3|mp4) 20 | 21 | 22 | kuana.characterDirs=3 23 | kuana.characterDirsWidth=2 24 | kuana.subdirectory=kuana 25 | # Pattern used for turning the content id into a file name. %s is replaced with the content id. 26 | kuana.filenameRegexPattern=%s 27 | 28 | kuanaradio.characterDirs=3 29 | kuanaradio.characterDirsWidth=2 30 | kuanaradio.subdirectory=kuana-radio 31 | # Pattern used for turning the content id into a file name. %s is replaced with the content id. 32 | kuanaradio.filenameRegexPattern=%s 33 | 34 | 35 | # Servers that the plugin depends on 36 | ticketCheckerLocation=http://iapetus:9651/ticket-system-service/tickets 37 | 38 | # Type used by ticket checker and content resolver for identifying content 39 | presentationType=Stream 40 | -------------------------------------------------------------------------------- /wowza-mediestream-vhost/src/main/config/wowza_vhost_mediestream/conf/mediestreamapple/wowza-modules.properties: -------------------------------------------------------------------------------- 1 | # 2 | # Property file for the Wowza Ticket Checker 3 | # 4 | 5 | # comma seperated list (no spaces) with the prefixes for each contentResolver 6 | # defined in the configurations in this property file 7 | contentResolverNames=doms,kuana,kuanaradio 8 | 9 | # Absolute path 10 | streamingStatisticsLogFolder=/home/wowza/logs 11 | 12 | # Number of characters to use for splitting content into directories. Example: if this is 2, the file 13 | # "hello.txt" will be in the path "h/e/hello.txt 14 | doms.characterDirs=4 15 | doms.characterDirsWidth=1 16 | # 17 | doms.subdirectory=doms 18 | # Pattern used for turning the content id into a file name. %s is replaced with the content id. 19 | doms.filenameRegexPattern=%s\\.(mp3|mp4) 20 | 21 | 22 | kuana.characterDirs=3 23 | kuana.characterDirsWidth=2 24 | kuana.subdirectory=kuana 25 | # Pattern used for turning the content id into a file name. %s is replaced with the content id. 26 | kuana.filenameRegexPattern=%s 27 | 28 | kuanaradio.characterDirs=3 29 | kuanaradio.characterDirsWidth=2 30 | kuanaradio.subdirectory=kuana-radio 31 | # Pattern used for turning the content id into a file name. %s is replaced with the content id. 32 | kuanaradio.filenameRegexPattern=%s 33 | 34 | 35 | # Servers that the plugin depends on 36 | ticketCheckerLocation=http://iapetus:9651/ticket-system-service/tickets 37 | 38 | # Type used by ticket checker and content resolver for identifying content 39 | presentationType=Stream 40 | -------------------------------------------------------------------------------- /wowza-mediestream-vhost/src/main/scripts/testmediestream.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | TICKETCHECKERSERVICE=http://deneb.statsbiblioteket.dk:9651/ticket-system-service 4 | WOWZAURL=rtmp://thalassa:1935/mediestream 5 | PROGRAM=d68a0380-012a-4cd8-8e5b-37adf6c2d47f 6 | IPADDR=$(hostname -i) 7 | TICKET=$(curl "$TICKETCHECKERSERVICE/tickets/issueTicket?id=doms_radioTVCollection:uuid:$PROGRAM&ipAddress=$IPADDR&type=Stream&SBIPRoleMapper=inhouse" 2> /dev/null|cut -d\" -f4) 8 | rtmpdump -q --stop=.1 -o /dev/null -r $WOWZAURL?ticket=$TICKET/flv:$PROGRAM.flv 9 | EXITCODE=$? 10 | if [ $EXITCODE -eq 2 ]; then 11 | exit 0 12 | else 13 | exit $EXITCODE 14 | fi 15 | -------------------------------------------------------------------------------- /wowza-mediestream-vhost/src/main/scripts/watchmisuse.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python2.6 2 | 3 | # Script that parses a log file from wowza and reports by mail users having streamed more than a given amount of streams 4 | # Usage: 5 | # watchmisuse.py 6 | # Example: 7 | # watchmisuse.py /home/wowza/logs/StreamingStat-$(date -d 'yesterday' +'%Y-%m-%d').log 20 kw@statsbiblioteket.dk,mvk@statsbiblioteket.dk "Mediestream STAGE" 8 | 9 | import json 10 | import sys 11 | import smtplib 12 | from email.mime.text import MIMEText 13 | 14 | count = {} 15 | maxcount = {} 16 | report = '' 17 | try: 18 | with open(sys.argv[1]) as f: 19 | firstline = 1 20 | for line in f: 21 | if firstline: 22 | firstline = 0 23 | continue 24 | parts = line.split(';',3) 25 | action = parts[1] 26 | attributes = json.loads(parts[3]) 27 | if attributes is None: 28 | continue 29 | user = attributes.get('eduPersonPrincipalName') 30 | if user: 31 | user = str(user) 32 | count.setdefault(user, 0) 33 | maxcount.setdefault(user, 0) 34 | if action == 'PLAY': 35 | count[user] = count[user]+1; 36 | maxcount[user] = max(count[user], maxcount[user]) 37 | elif action == 'STOP': 38 | count[user] = count[user]-1; 39 | except IOError: 40 | exit 41 | for c in maxcount: 42 | if maxcount[c] >= int(sys.argv[2]): 43 | report += 'User {0} has streamed {1} simultaneous streams.\n'.format(c, maxcount[c]) 44 | if report: 45 | msg = MIMEText(report) 46 | msg['Subject'] = sys.argv[4] + ' misuse report' 47 | msg['To'] = sys.argv[3]; 48 | msg['From'] = 'statsbiblioteket@statsbiblioteket.dk' 49 | s = smtplib.SMTP('post.statsbiblioteket.dk') 50 | s.sendmail('statsbiblioteket@statsbiblioteket.dk', sys.argv[3], msg.as_string()) 51 | s.quit() 52 | -------------------------------------------------------------------------------- /wowza-mediestream-vhost/src/main/scripts/watchplayer.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | 3 | # Script that parses a log file from wowza and reports by mail if streams have been played with different referrer than jwplayer 4 | # Usage: 5 | # watchplayer.py 6 | # Example: 7 | # watchplayer.py /home/wowza/wowza/logs/wowzamediaserver_access.log.$(date -d 'yesterday' +'%Y-%m-%d') kw@statsbiblioteket.dk,mvk@statsbiblioteket.dk "Mediestream STAGE" 8 | 9 | import sys 10 | import smtplib 11 | from email.mime.text import MIMEText 12 | 13 | players = {} 14 | report = '' 15 | try: 16 | with open(sys.argv[1]) as f: 17 | for line in f: 18 | parts = line.split('\t') 19 | if len(parts) < 18: 20 | continue 21 | action = parts[3] 22 | if action == 'play': 23 | player = parts[18] 24 | players.setdefault(player, 0) 25 | players[player] = players[player]+1 26 | except IOError: 27 | exit 28 | for p in players: 29 | if not(p.endswith('jwplayer.flash.swf')): 30 | report += 'Streams have been played with non-approved player \'{0}\' {1} times.\n'.format(p, players[p]) 31 | if report: 32 | msg = MIMEText(report) 33 | msg['Subject'] = sys.argv[3] + ' misuse report' 34 | msg['To'] = sys.argv[2]; 35 | msg['From'] = 'statsbiblioteket@statsbiblioteket.dk' 36 | s = smtplib.SMTP('post.statsbiblioteket.dk') 37 | s.sendmail('statsbiblioteket@statsbiblioteket.dk', sys.argv[2], msg.as_string()) 38 | s.quit() 39 | -------------------------------------------------------------------------------- /wowza-statistics-module/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4.0.0 4 | 5 | 6 | dk.statsbiblioteket.medieplatform 7 | wowza-modules 8 | 4.8-SNAPSHOT 9 | 10 | 11 | wowza-statistics-module 12 | 13 | 14 | 15 | ${project.groupId} 16 | wowza-common 17 | 18 | 19 | 20 | ${project.groupId} 21 | wowza-ticket-checker-module 22 | 23 | 24 | 25 | com.wms 26 | wms-server 27 | provided 28 | 29 | 30 | 31 | com.wms 32 | wms-bootstrap 33 | provided 34 | 35 | 36 | 37 | com.wms 38 | wms-core 39 | provided 40 | 41 | 42 | 43 | com.wms 44 | wms-stream-publish 45 | provided 46 | 47 | 48 | 49 | com.wms 50 | wms-transcoder 51 | provided 52 | 53 | 54 | 55 | com.wms 56 | wms-rest 57 | provided 58 | 59 | 60 | 61 | com.wms 62 | wms-pushpublish 63 | provided 64 | 65 | 66 | 67 | com.wms 68 | wms-sourcecontrol 69 | provided 70 | 71 | 72 | 73 | com.wms 74 | wms-webrtc 75 | provided 76 | 77 | 78 | 79 | com.wms 80 | wms-mediacache 81 | provided 82 | 83 | 84 | 85 | log4j 86 | log4j 87 | provided 88 | 89 | 90 | 91 | org.bouncycastle 92 | bcprov-jdk15on 93 | provided 94 | 95 | 96 | 97 | commons-lang 98 | commons-lang 99 | provided 100 | 101 | 102 | 103 | org.junit.jupiter 104 | junit-jupiter-engine 105 | test 106 | 107 | 108 | org.mockito 109 | mockito-core 110 | test 111 | 112 | 113 | -------------------------------------------------------------------------------- /wowza-statistics-module/src/main/java/dk/statsbiblioteket/medieplatform/wowza/plugin/StreamingStatisticsIMediaStreamActionNotify2.java: -------------------------------------------------------------------------------- 1 | package dk.statsbiblioteket.medieplatform.wowza.plugin; 2 | 3 | import com.wowza.wms.amf.AMFPacket; 4 | import com.wowza.wms.stream.IMediaStream; 5 | import com.wowza.wms.stream.IMediaStreamActionNotify2; 6 | 7 | import dk.statsbiblioteket.medieplatform.wowza.plugin.streamingstatistics.StreamingEventLogger; 8 | 9 | /** 10 | * This class handles logging of users actually playing the video 11 | */ 12 | public class StreamingStatisticsIMediaStreamActionNotify2 implements IMediaStreamActionNotify2 { 13 | 14 | private final StreamingEventLogger streamingEventLogger; 15 | 16 | public StreamingStatisticsIMediaStreamActionNotify2(StreamingEventLogger streamingEventLogger) { 17 | this.streamingEventLogger = streamingEventLogger; 18 | } 19 | 20 | private static String getQueryString(IMediaStream stream) { 21 | return stream.getClient().getQueryStr(); 22 | } 23 | 24 | private static String getStreamingUrl(IMediaStream stream) { 25 | return stream.getClient().getUri() + '?' + stream.getClient().getQueryStr() + '/' + stream.getExt() + ':' 26 | + stream.getName(); 27 | } 28 | 29 | public void onPlay(IMediaStream stream, String streamName, double playStart, double playLen, int playReset) { 30 | streamingEventLogger.logUserEventPlay(getQueryString(stream), 31 | getStreamingUrl(stream)); 32 | } 33 | 34 | public void onMetaData(IMediaStream stream, AMFPacket metaDataPacket) { 35 | // Do nothing 36 | } 37 | 38 | public void onPauseRaw(IMediaStream stream, boolean isPause, double location) { 39 | streamingEventLogger.logUserEventPause(getQueryString(stream), 40 | getStreamingUrl(stream)); 41 | } 42 | 43 | public void onSeek(IMediaStream stream, double location) { 44 | streamingEventLogger.logUserEventSeek(getQueryString(stream), 45 | getStreamingUrl(stream)); 46 | } 47 | 48 | public void onStop(IMediaStream stream) { 49 | streamingEventLogger.logUserEventStop(getQueryString(stream), 50 | getStreamingUrl(stream)); 51 | } 52 | 53 | public void onUnPublish(IMediaStream stream, String streamName, boolean isRecord, boolean isAppend) { 54 | // Do nothing 55 | } 56 | 57 | public void onPublish(IMediaStream stream, String streamName, boolean isRecord, boolean isAppend) { 58 | // Do nothing 59 | } 60 | 61 | public void onPause(IMediaStream stream, boolean isPause, double location) { 62 | streamingEventLogger.logUserEventPause(getQueryString(stream), 63 | getStreamingUrl(stream)); 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /wowza-statistics-module/src/main/java/dk/statsbiblioteket/medieplatform/wowza/plugin/streamingstatistics/StreamingEventLogger.java: -------------------------------------------------------------------------------- 1 | package dk.statsbiblioteket.medieplatform.wowza.plugin.streamingstatistics; 2 | 3 | import java.io.BufferedWriter; 4 | import java.io.File; 5 | import java.io.IOException; 6 | import java.nio.charset.StandardCharsets; 7 | import java.nio.file.Files; 8 | import java.nio.file.StandardOpenOption; 9 | import java.text.SimpleDateFormat; 10 | import java.time.LocalDate; 11 | import java.time.LocalDateTime; 12 | import java.time.LocalTime; 13 | import java.time.ZoneId; 14 | import java.util.Date; 15 | import java.util.Locale; 16 | 17 | import com.wowza.wms.logging.WMSLogger; 18 | 19 | import dk.statsbiblioteket.medieplatform.ticketsystem.Ticket; 20 | import dk.statsbiblioteket.medieplatform.wowza.plugin.streamingstatistics.StreamingStatLogEntry.Event; 21 | import dk.statsbiblioteket.medieplatform.wowza.plugin.ticket.TicketToolInterface; 22 | import dk.statsbiblioteket.medieplatform.wowza.plugin.utilities.IllegallyFormattedQueryStringException; 23 | import dk.statsbiblioteket.medieplatform.wowza.plugin.utilities.StringAndTextUtil; 24 | 25 | public class StreamingEventLogger { 26 | private static final String DATE_PATTERN = "yyyy-MM-dd"; 27 | public static final String FILENAME_PREFIX = "StreamingStat-"; 28 | private String statLogFileHomeDir; 29 | private BufferedWriter statLogWriter; 30 | private Date dateForNewLogFile; 31 | 32 | private WMSLogger logger; 33 | private TicketToolInterface ticketTool; 34 | private String newlineString; 35 | 36 | public StreamingEventLogger(TicketToolInterface ticketTool, WMSLogger logger, String statLogFileHomeDir) { 37 | super(); 38 | this.logger = logger; 39 | this.ticketTool = ticketTool; 40 | this.statLogFileHomeDir = statLogFileHomeDir; 41 | this.statLogWriter = null; 42 | logger.info("Statistics logger " + this.getClass().getName() + " has been created, logging files to '" 43 | + statLogFileHomeDir + "'."); 44 | this.dateForNewLogFile = new Date(); 45 | this.newlineString = System.getProperty("line.separator"); 46 | } 47 | 48 | public void logUserEventPlay(String queryString, String streamingUrl) { 49 | logUserEvent(Event.PLAY, queryString, streamingUrl); 50 | } 51 | 52 | public void logUserEventStop(String queryString, String streamingUrl) { 53 | logUserEvent(Event.STOP, queryString, streamingUrl); 54 | } 55 | 56 | public void logUserEventPause(String queryString, String streamingUrl) { 57 | logUserEvent(Event.PAUSE, queryString, streamingUrl); 58 | } 59 | 60 | public void logUserEventSeek(String queryString, String streamingUrl) { 61 | logUserEvent(Event.SEEK, queryString, streamingUrl); 62 | } 63 | 64 | /** 65 | * Log the given event 66 | * @param event The event to log 67 | * @param queryString Query string to read parameters for 68 | * @param streamingURL The URL or this stream 69 | */ 70 | private void logUserEvent(Event event, String queryString, String streamingURL) { 71 | if (queryString == null) { 72 | logger.warn("No logging was performed. Query string of client could not be found."); 73 | return; 74 | } 75 | try { 76 | Ticket streamingTicket = StringAndTextUtil.getTicket(queryString, ticketTool); 77 | String logString = new StreamingStatLogEntry(event, streamingTicket, streamingURL).getLogString(); 78 | writeEventLog(logString); 79 | } catch (IllegallyFormattedQueryStringException e) { 80 | logger.warn("No logging was performed. Query string of client does not match expected format. Was " 81 | + queryString); 82 | } 83 | } 84 | 85 | protected synchronized void writeEventLog(String logString) { 86 | try { 87 | BufferedWriter statLogWriter = getStatLogWriter(); 88 | statLogWriter.write(logString); 89 | statLogWriter.write(this.newlineString); 90 | statLogWriter.flush(); 91 | } catch (IOException e) { 92 | logger.error("An IO-error occured when writing statistics log.", e); 93 | } 94 | } 95 | 96 | protected BufferedWriter getStatLogWriter() throws IOException { 97 | File currentStatLogFile; 98 | Date now = new Date(); 99 | if ((statLogWriter == null) || (this.dateForNewLogFile.before(now))) { 100 | if (statLogWriter != null) { 101 | statLogWriter.close(); 102 | } 103 | String filenameWithCorrectDate = getFilename(now); 104 | currentStatLogFile = new File(this.statLogFileHomeDir, filenameWithCorrectDate); 105 | this.logger.info("Creating log file: " + currentStatLogFile.getAbsolutePath()); 106 | this.dateForNewLogFile = getFollowingMidnight(now); 107 | boolean newLogFile = !currentStatLogFile.exists(); 108 | this.statLogWriter = Files.newBufferedWriter(currentStatLogFile.toPath(), StandardCharsets.UTF_8, 109 | StandardOpenOption.APPEND, StandardOpenOption.WRITE, StandardOpenOption.CREATE); 110 | if (newLogFile) { 111 | this.statLogWriter.write(StreamingStatLogEntry.getLogStringHeadline()); 112 | this.statLogWriter.write(this.newlineString); 113 | this.statLogWriter.flush(); 114 | } 115 | } 116 | return statLogWriter; 117 | } 118 | 119 | protected Date getFollowingMidnight(Date date) { 120 | ZoneId zone = ZoneId.of("Europe/Copenhagen"); 121 | LocalDate localDate = date.toInstant().atZone(zone).toLocalDate(); 122 | LocalDateTime tomorroMidnight = LocalDateTime.of(localDate, LocalTime.MIDNIGHT).plusDays(1); 123 | return Date.from(tomorroMidnight.atZone(zone).toInstant()); 124 | } 125 | 126 | protected void setDateForNewLogFile(Date dateForNewLogFile) { 127 | this.dateForNewLogFile = dateForNewLogFile; 128 | } 129 | 130 | public static String getFilename(Date time) { 131 | SimpleDateFormat sdf = new SimpleDateFormat(DATE_PATTERN, Locale.ROOT); 132 | return FILENAME_PREFIX + sdf.format(time) + ".log"; 133 | } 134 | } 135 | -------------------------------------------------------------------------------- /wowza-statistics-module/src/main/java/dk/statsbiblioteket/medieplatform/wowza/plugin/streamingstatistics/StreamingStatLogEntry.java: -------------------------------------------------------------------------------- 1 | package dk.statsbiblioteket.medieplatform.wowza.plugin.streamingstatistics; 2 | 3 | import com.fasterxml.jackson.databind.ObjectMapper; 4 | import dk.statsbiblioteket.medieplatform.ticketsystem.Ticket; 5 | 6 | import java.io.IOException; 7 | import java.text.SimpleDateFormat; 8 | import java.util.Date; 9 | import java.util.Locale; 10 | 11 | public class StreamingStatLogEntry { 12 | private static final String DATE_PATTERN = "yyyy-MM-dd HH:mm:ss.SSS"; 13 | 14 | public enum Event {PLAY, PAUSE, STOP, SEEK} 15 | 16 | // Log information 17 | private Date timestamp; 18 | 19 | private String streamingURL; 20 | private Event event; 21 | 22 | private String userAttributesAsJson; // Contains user roles 23 | 24 | public StreamingStatLogEntry(Event event, Ticket streamingTicket, String streamingURL) { 25 | this.timestamp = new Date(); 26 | 27 | this.streamingURL = streamingURL; 28 | this.event = event; 29 | 30 | if ((streamingTicket != null)) { 31 | this.userAttributesAsJson = retrieveTicketInformation(streamingTicket); 32 | } else { 33 | this.userAttributesAsJson = null; 34 | } 35 | } 36 | 37 | /** 38 | * Extract information for the log line from a streaming ticket 39 | * @param streamingTicket The ticket from which to extract information for the log line 40 | */ 41 | private static String retrieveTicketInformation(Ticket streamingTicket) { 42 | ObjectMapper mapper = new ObjectMapper(); 43 | try { 44 | return mapper.writeValueAsString(streamingTicket.getUserAttributes()); 45 | } catch (IOException e) { 46 | //Should never happen; string could not be read 47 | return null; 48 | } 49 | } 50 | 51 | public Event getEvent() { 52 | return event; 53 | } 54 | 55 | /** 56 | * Build the log line from gathered information 57 | * @return The log line 58 | */ 59 | public String getLogString() { 60 | SimpleDateFormat sdf = new SimpleDateFormat(DATE_PATTERN, Locale.ROOT); 61 | StringBuilder sb = new StringBuilder(); 62 | sb.append(sdf.format(timestamp)); 63 | sb.append(";"); 64 | sb.append(getEvent()); 65 | sb.append(";"); 66 | sb.append(escapeLogString(streamingURL)); 67 | sb.append(";"); 68 | sb.append(escapeLogString(userAttributesAsJson)); 69 | return sb.toString(); 70 | } 71 | 72 | /** 73 | * Build the headline for the log 74 | * @return The headline for the log 75 | */ 76 | public static String getLogStringHeadline() { 77 | StringBuilder sb = new StringBuilder(); 78 | sb.append("Timestamp"); 79 | sb.append(";"); 80 | sb.append("Event"); 81 | sb.append(";"); 82 | sb.append("Streaming URL"); 83 | sb.append(";"); 84 | sb.append("User attributes"); 85 | return sb.toString(); 86 | } 87 | 88 | protected String escapeLogString(String logLine) { 89 | if (logLine == null) { 90 | return null; 91 | } 92 | return logLine.replaceAll(";", "[semicolon]"); 93 | } 94 | 95 | @Override 96 | public String toString() { 97 | return "StreamingStatLogEntry: " + getLogString(); 98 | } 99 | } 100 | -------------------------------------------------------------------------------- /wowza-statistics-module/src/test/java/dk/statsbiblioteket/medieplatform/wowza/plugin/streamingstatistics/StreamingStatLogEntryTest.java: -------------------------------------------------------------------------------- 1 | package dk.statsbiblioteket.medieplatform.wowza.plugin.streamingstatistics; 2 | 3 | import java.util.Arrays; 4 | import java.util.HashMap; 5 | import java.util.List; 6 | import java.util.Map; 7 | 8 | import org.junit.jupiter.api.AfterEach; 9 | import org.junit.jupiter.api.BeforeEach; 10 | import org.junit.jupiter.api.Test; 11 | import static org.junit.jupiter.api.Assertions.*; 12 | import static org.mockito.Mockito.mock; 13 | import static org.mockito.Mockito.when; 14 | 15 | import dk.statsbiblioteket.medieplatform.ticketsystem.Ticket; 16 | import dk.statsbiblioteket.medieplatform.wowza.plugin.streamingstatistics.StreamingStatLogEntry.Event; 17 | 18 | 19 | public class StreamingStatLogEntryTest { 20 | 21 | @BeforeEach 22 | public void setUp() throws Exception { 23 | org.apache.log4j.BasicConfigurator.configure(); 24 | } 25 | 26 | @AfterEach 27 | public void tearDown() throws Exception { 28 | org.apache.log4j.BasicConfigurator.resetConfiguration(); 29 | } 30 | 31 | @Test 32 | public void testConstructorValueMapping() { 33 | // Setup ticket 34 | Ticket ticket = mock(Ticket.class); 35 | Map> userAttr = new HashMap>(); 36 | userAttr.put("schacHomeOrganization", Arrays.asList("au.dk")); 37 | userAttr.put("eduPersonTargetedID", Arrays.asList("1x1")); 38 | when(ticket.getUserAttributes()).thenReturn(userAttr); 39 | 40 | Event logEvent = Event.PLAY; 41 | // Test 42 | StreamingStatLogEntry logEntry = new StreamingStatLogEntry(logEvent, ticket, ""); 43 | // Validate 44 | assertEquals(Event.PLAY, logEntry.getEvent(), "StreamingStatLogEntry value"); 45 | assertTrue(logEntry.getLogString().contains("\"schacHomeOrganization\":[\"au.dk\"]")); 46 | assertTrue(logEntry.getLogString().contains("\"eduPersonTargetedID\":[\"1x1\"]")); 47 | } 48 | 49 | @Test 50 | public void testGetLogStringHeadline() { 51 | // Setup ticket 52 | Ticket ticket = mock(Ticket.class); 53 | Map> userAttr = new HashMap>(); 54 | userAttr.put("schacHomeOrganization", Arrays.asList("au.dk")); 55 | userAttr.put("eduPersonTargetedID", Arrays.asList("1x1")); 56 | when(ticket.getUserAttributes()).thenReturn(userAttr); 57 | 58 | Event logEvent = Event.PLAY; 59 | // Test 60 | String logEntry = new StreamingStatLogEntry(logEvent, ticket, "").getLogString(); 61 | String logHeader = StreamingStatLogEntry.getLogStringHeadline(); 62 | assertEquals(logEntry.split(";").length, logHeader.split(";").length, 63 | "Expected same amount of entries in header and logline"); 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /wowza-ticket-checker-module/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4.0.0 4 | 5 | 6 | dk.statsbiblioteket.medieplatform 7 | wowza-modules 8 | 4.8-SNAPSHOT 9 | 10 | 11 | wowza-ticket-checker-module 12 | 13 | 14 | 15 | 16 | dk.statsbiblioteket.medieplatform 17 | wowza-common 18 | 19 | 20 | 21 | com.wms 22 | wms-server 23 | provided 24 | 25 | 26 | 27 | com.wms 28 | wms-bootstrap 29 | provided 30 | 31 | 32 | 33 | com.wms 34 | wms-core 35 | provided 36 | 37 | 38 | 39 | com.wms 40 | wms-transcoder 41 | provided 42 | 43 | 44 | 45 | com.wms 46 | wms-rest 47 | provided 48 | 49 | 50 | 51 | com.wms 52 | wms-pushpublish 53 | provided 54 | 55 | 56 | 57 | com.wms 58 | wms-stream-publish 59 | provided 60 | 61 | 62 | 63 | com.wms 64 | wms-sourcecontrol 65 | provided 66 | 67 | 68 | 69 | com.wms 70 | wms-webrtc 71 | provided 72 | 73 | 74 | 75 | com.wms 76 | wms-mediacache 77 | provided 78 | 79 | 80 | 81 | log4j 82 | log4j 83 | provided 84 | 85 | 86 | 87 | org.bouncycastle 88 | bcprov-jdk15on 89 | provided 90 | 91 | 92 | 93 | commons-lang 94 | commons-lang 95 | provided 96 | 97 | 98 | 99 | com.fasterxml.jackson.jaxrs 100 | jackson-jaxrs-json-provider 101 | 102 | 103 | 104 | org.apache.cxf 105 | cxf-rt-rs-client 106 | 107 | 108 | 109 | org.junit.jupiter 110 | junit-jupiter-engine 111 | test 112 | 113 | 114 | org.mockito 115 | mockito-core 116 | test 117 | 118 | 119 | 120 | 121 | -------------------------------------------------------------------------------- /wowza-ticket-checker-module/src/main/java/dk/statsbiblioteket/medieplatform/wowza/plugin/StreamAuthenticator.java: -------------------------------------------------------------------------------- 1 | package dk.statsbiblioteket.medieplatform.wowza.plugin; 2 | 3 | import com.wowza.wms.stream.IMediaStream; 4 | import com.wowza.wms.stream.MediaStreamActionNotify3Base; 5 | 6 | /** 7 | * Action notifier that kills a stream that is not allowed by the ticket. 8 | */ 9 | class StreamAuthenticator extends MediaStreamActionNotify3Base { 10 | 11 | private TicketChecker ticketChecker; 12 | 13 | /** 14 | * Initialise the notifier. 15 | * 16 | * @param ticketChecker The ticket checker to use when checking tickets. 17 | */ 18 | public StreamAuthenticator(TicketChecker ticketChecker) { 19 | super(); 20 | this.ticketChecker = ticketChecker; 21 | } 22 | 23 | /** 24 | * Check the stream name against a ticket extracted from the stream. 25 | * Close the stream if the ticket does not allow this stream. 26 | * Called when a stream gets a play event. 27 | * 28 | * @param stream The stream that is checked by the ticket checker. 29 | * @param streamName Name of stream. Not used. 30 | * @param playStart Play start. Not used. 31 | * @param playLen Play length. Not used. 32 | * @param playReset Play reset. Not used. 33 | */ 34 | public void onPlay(IMediaStream stream, String streamName, double playStart, 35 | double playLen, int playReset) { 36 | if (!ticketChecker.checkTicket(stream, stream.getClient())) { 37 | stream.getClient().rejectConnection("Streaming not allowed"); 38 | stream.sendStreamNotFound("Streaming not allowed"); 39 | stream.getClient().setShutdownClient(true); 40 | stream.getClient().shutdownClient(); 41 | } 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /wowza-ticket-checker-module/src/main/java/dk/statsbiblioteket/medieplatform/wowza/plugin/TicketChecker.java: -------------------------------------------------------------------------------- 1 | package dk.statsbiblioteket.medieplatform.wowza.plugin; 2 | 3 | import com.wowza.wms.client.IClient; 4 | import com.wowza.wms.httpstreamer.model.IHTTPStreamerSession; 5 | import com.wowza.wms.logging.WMSLogger; 6 | import com.wowza.wms.logging.WMSLoggerFactory; 7 | import com.wowza.wms.stream.IMediaStream; 8 | 9 | import dk.statsbiblioteket.medieplatform.ticketsystem.Ticket; 10 | import dk.statsbiblioteket.medieplatform.wowza.plugin.ticket.TicketToolInterface; 11 | import dk.statsbiblioteket.medieplatform.wowza.plugin.utilities.IllegallyFormattedQueryStringException; 12 | import dk.statsbiblioteket.medieplatform.wowza.plugin.utilities.StringAndTextUtil; 13 | 14 | /** 15 | * This class is used to validate the ticket 16 | */ 17 | public class TicketChecker { 18 | private final WMSLogger logger; 19 | private final String presentationType; 20 | private final TicketToolInterface ticketTool; 21 | 22 | public TicketChecker(String presentationType, TicketToolInterface ticketTool) { 23 | super(); 24 | this.presentationType = presentationType; 25 | this.logger = WMSLoggerFactory.getLogger(this.getClass()); 26 | this.ticketTool = ticketTool; 27 | } 28 | 29 | /** 30 | * Check if a stream is allowed to play 31 | * 32 | * @param stream the stream to check 33 | * @param client the client trying to play the stream 34 | * @return true if allowed, false otherwise. 35 | * @see #checkTicket(java.lang.String, java.lang.String, java.lang.String) 36 | */ 37 | public boolean checkTicket(IMediaStream stream, IClient client) { 38 | if (client == null) { 39 | logger.debug("No client, returning ", stream); 40 | return false; 41 | } 42 | return checkTicket(stream.getName(), client.getQueryStr(), getClientIp(client)); 43 | } 44 | 45 | /** 46 | * Check if a stream is allowed to play. 47 | *

48 | * Extracts streamname, query string and client ip from the http session 49 | * 50 | * @param httpSession The http session 51 | * @return true if allowed, false otherwise. 52 | * @see #checkTicket(java.lang.String, java.lang.String, java.lang.String) 53 | */ 54 | public boolean checkTicket(IHTTPStreamerSession httpSession) { 55 | return checkTicket(httpSession.getStreamName(), httpSession.getQueryStr(), getClientIp(httpSession)); 56 | } 57 | 58 | private boolean checkTicket(String name, String query, String ip) { 59 | logger.trace( 60 | "checkTicket(String name=" + name 61 | + ", String query=" + query + ")"); 62 | try { 63 | Ticket streamingTicket = StringAndTextUtil.getTicket(query, ticketTool); 64 | logger.debug("Ticket received: " + (streamingTicket != null ? streamingTicket.getId() : "null")); 65 | if ( 66 | streamingTicket != null && 67 | isClientAllowed(streamingTicket, ip) && 68 | ticketForThisPresentationType(streamingTicket) && 69 | doesTicketAllowThisStream(name, streamingTicket) 70 | ) { 71 | logger.info( 72 | "checkTicket(String name=" + name 73 | + ", String query=" + query + ") successful."); 74 | return true; 75 | } else { 76 | logger.info("Client not allowed to get content streamed for String name=" + name 77 | + ", String query=" + query 78 | + ")"); 79 | return false; 80 | } 81 | } catch (IllegallyFormattedQueryStringException e) { 82 | logger.warn("Illegally formatted query string [" + query + "]."); 83 | return false; 84 | } 85 | } 86 | 87 | private boolean ticketForThisPresentationType(Ticket streamingTicket) { 88 | return streamingTicket.getType().equals(presentationType); 89 | } 90 | 91 | private boolean doesTicketAllowThisStream(String name, Ticket streamingTicket) { 92 | name = clean(name); 93 | for (String resource : streamingTicket.getResources()) { 94 | if (resource.contains(name)){ 95 | return true; 96 | } 97 | } 98 | return false; 99 | } 100 | 101 | /** 102 | * This method checks if the ticket is given to the same IP address as the client 103 | * @param streamingTicket the ticket 104 | * @param ip ip of client 105 | * @return true if the ip is the same for the ticket and the user 106 | */ 107 | private boolean isClientAllowed(Ticket streamingTicket, String ip) { 108 | 109 | boolean isAllowed = (ip != null) && (ip.equals(streamingTicket.getIpAddress())); 110 | logger.debug("isClientAllowed - ipOfClient: " + ip + ", streamingTicket.getIpAddress(): " 111 | + streamingTicket.getIpAddress() + ", isAllowed: " + isAllowed); 112 | return isAllowed; 113 | } 114 | 115 | private String clean(String name) { 116 | if (name.contains(".")){ 117 | name = name.substring(0, name.indexOf(".")); 118 | } 119 | if (name.contains(":")) { 120 | name = name.substring(name.lastIndexOf(':') + 1); 121 | } 122 | 123 | return name; 124 | } 125 | 126 | private String getClientIp(IClient client) { 127 | String IP = (client.getForwardedIP​()) != null ? client.getForwardedIP​() : client.getIp(); 128 | return IP; 129 | } 130 | 131 | private String getClientIp(IHTTPStreamerSession httpSession) { 132 | String IP = (httpSession.getForwardedIP​()) != null ? httpSession.getForwardedIP​() : httpSession.getIpAddress​(); 133 | return IP; 134 | } 135 | } 136 | -------------------------------------------------------------------------------- /wowza-ticket-checker-module/src/main/java/dk/statsbiblioteket/medieplatform/wowza/plugin/ticket/TicketTool.java: -------------------------------------------------------------------------------- 1 | package dk.statsbiblioteket.medieplatform.wowza.plugin.ticket; 2 | 3 | import java.util.Arrays; 4 | 5 | import javax.ws.rs.WebApplicationException; 6 | import javax.ws.rs.core.Response.StatusType; 7 | 8 | import org.apache.cxf.jaxrs.client.WebClient; 9 | 10 | import com.fasterxml.jackson.jaxrs.json.JacksonJaxbJsonProvider; 11 | import com.wowza.wms.logging.WMSLogger; 12 | 13 | import dk.statsbiblioteket.medieplatform.ticketsystem.Ticket; 14 | 15 | public class TicketTool implements TicketToolInterface { 16 | 17 | private WMSLogger logger; 18 | private final String serviceUrl; 19 | 20 | public TicketTool(String serviceURL, WMSLogger logger) { 21 | super(); 22 | this.serviceUrl = serviceURL; 23 | this.logger = logger; 24 | } 25 | 26 | /* (non-Javadoc) 27 | * @see dk.statsbiblioteket.medieplatform.wowza.plugin.ticket.TicketToolInterface#resolveTicket(java.lang.String) 28 | */ 29 | @Override 30 | public Ticket resolveTicket(String ticketID) { 31 | WebClient client = getWebclient(); 32 | try { 33 | Ticket ticketXml = client.path("/resolveTicket/").path(ticketID).get(Ticket.class); 34 | logger.debug("resolveTicket: Ticket received: '" + ticketID + "'"); 35 | return ticketXml; 36 | 37 | } catch (WebApplicationException e) { 38 | StatusType responseStatus = e.getResponse().getStatusInfo(); 39 | logger.debug("The session might have timed out for ticket '" 40 | + ticketID + "'. Ticket service response status: " + responseStatus.getStatusCode()); 41 | return null; 42 | } finally { 43 | client.close(); 44 | } 45 | } 46 | 47 | private WebClient getWebclient() { 48 | WebClient client = WebClient.create(serviceUrl, Arrays.asList(new JacksonJaxbJsonProvider())); 49 | return client; 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /wowza-ticket-checker-module/src/test/java/dk/statsbiblioteket/medieplatform/wowza/plugin/TicketCheckerTest.java: -------------------------------------------------------------------------------- 1 | package dk.statsbiblioteket.medieplatform.wowza.plugin; 2 | 3 | import com.wowza.wms.application.IApplicationInstance; 4 | import com.wowza.wms.client.IClient; 5 | import com.wowza.wms.logging.WMSLoggerFactory; 6 | import com.wowza.wms.stream.IMediaStream; 7 | import org.apache.log4j.Logger; 8 | import org.junit.jupiter.api.AfterEach; 9 | import org.junit.jupiter.api.BeforeEach; 10 | import org.junit.jupiter.api.Test; 11 | import static org.junit.jupiter.api.Assertions.*; 12 | import org.mockito.invocation.InvocationOnMock; 13 | 14 | import dk.statsbiblioteket.medieplatform.ticketsystem.Property; 15 | import dk.statsbiblioteket.medieplatform.ticketsystem.Ticket; 16 | import dk.statsbiblioteket.medieplatform.wowza.plugin.ticket.TicketToolInterface; 17 | 18 | import static org.mockito.Mockito.mock; 19 | import static org.mockito.Mockito.when; 20 | import static org.mockito.ArgumentMatchers.*; 21 | 22 | import java.util.ArrayList; 23 | import java.util.Arrays; 24 | import java.util.HashMap; 25 | import java.util.List; 26 | import java.util.Map; 27 | 28 | 29 | public class TicketCheckerTest { 30 | 31 | public static final String QUERY_STRING = "ticket="; 32 | private Logger logger; 33 | 34 | TicketToolInterface ticketTool; 35 | 36 | IApplicationInstance iAppInstance = mock(IApplicationInstance.class); 37 | 38 | String goodIP = "127.0.0.1"; 39 | String badIP = "127.0.0.2-Invalid-ip"; 40 | String programID = "0ef8f946-4e90-4c9d-843a-a03504d2ee6c"; 41 | 42 | String name = "0ef8f946-4e90-4c9d-843a-a03504d2ee6c.flv"; 43 | 44 | 45 | public TicketCheckerTest() { 46 | super(); 47 | this.logger = WMSLoggerFactory.getLogger(this.getClass()); 48 | } 49 | 50 | @BeforeEach 51 | public void setUp() throws Exception { 52 | org.apache.log4j.BasicConfigurator.configure(); 53 | ticketTool = mock(TicketToolInterface.class); 54 | } 55 | 56 | @AfterEach 57 | public void tearDown() throws Exception { 58 | org.apache.log4j.BasicConfigurator.resetConfiguration(); 59 | } 60 | 61 | @Test 62 | public void testUserNotAllowedToPlayFile() { 63 | // Setup environment 64 | Map tickets = new HashMap<>(); 65 | Ticket ticket = getTicket(badIP, programID); 66 | tickets.put(ticket.getId(), ticket); 67 | when(ticketTool.resolveTicket(anyString())).thenAnswer( 68 | (InvocationOnMock invocation) -> tickets.get((String) invocation.getArguments()[0])); 69 | 70 | String queryString = QUERY_STRING + ticket.getId(); 71 | 72 | IClient iClient = mock(IClient.class); 73 | when(iClient.getQueryStr()).thenReturn(queryString); 74 | IMediaStream stream = mock(IMediaStream.class); 75 | when(stream.getClient()).thenReturn(iClient); 76 | when(stream.getQueryStr()).thenReturn(queryString); 77 | when(stream.getName()).thenReturn(name); 78 | TicketChecker ticketChecker = new TicketChecker("Stream", ticketTool); 79 | // Run test 80 | boolean result = ticketChecker.checkTicket(stream, stream.getClient()); 81 | // Validate result 82 | assertFalse(result, "Expected not to be allowed"); 83 | } 84 | 85 | @Test 86 | public void testNonExistingTicket() { 87 | // Setup environment 88 | String queryString = QUERY_STRING + "InvalidID"; 89 | 90 | IClient iClient = mock(IClient.class); 91 | when(iClient.getQueryStr()).thenReturn(queryString); 92 | IMediaStream stream = mock(IMediaStream.class); 93 | when(stream.getClient()).thenReturn(iClient); 94 | when(stream.getQueryStr()).thenReturn(queryString); 95 | when(stream.getName()).thenReturn(name); 96 | TicketChecker ticketChecker = new TicketChecker("Stream", ticketTool); 97 | // Run test 98 | boolean result = ticketChecker.checkTicket(stream, stream.getClient()); 99 | // Validate result 100 | assertFalse(result, "Expected not to be allowed"); 101 | } 102 | 103 | @Test 104 | public void testGetFileToStreamSucces() { 105 | // Setup 106 | Map tickets = new HashMap<>(); 107 | Ticket ticket = getTicket(goodIP, programID); 108 | tickets.put(ticket.getId(), ticket); 109 | when(ticketTool.resolveTicket(anyString())).thenAnswer( 110 | (InvocationOnMock invocation) -> tickets.get((String) invocation.getArguments()[0])); 111 | 112 | String queryString = QUERY_STRING + ticket.getId(); 113 | 114 | IClient iClient = mock(IClient.class); 115 | when(iClient.getQueryStr()).thenReturn(queryString); 116 | when(iClient.getIp()).thenReturn(goodIP); 117 | IMediaStream stream = mock(IMediaStream.class); 118 | when(stream.getClient()).thenReturn(iClient); 119 | when(stream.getQueryStr()).thenReturn(queryString); 120 | when(stream.getName()).thenReturn(name); 121 | TicketChecker ticketChecker = new TicketChecker("Stream", ticketTool); 122 | // Test 123 | boolean result = ticketChecker.checkTicket(stream, stream.getClient()); 124 | // Validate 125 | assertTrue(result, "Expected success"); 126 | } 127 | 128 | @Test 129 | public void testWrongProgramId() { 130 | // Setup 131 | Map tickets = new HashMap<>(); 132 | Ticket ticket = getTicket(goodIP, "anotherprogram"); 133 | tickets.put(ticket.getId(), ticket); 134 | when(ticketTool.resolveTicket(anyString())).thenAnswer( 135 | (InvocationOnMock invocation) -> tickets.get((String) invocation.getArguments()[0])); 136 | 137 | String queryString = QUERY_STRING + ticket.getId(); 138 | 139 | IClient iClient = mock(IClient.class); 140 | when(iClient.getQueryStr()).thenReturn(queryString); 141 | IMediaStream stream = mock(IMediaStream.class); 142 | when(stream.getClient()).thenReturn(iClient); 143 | when(stream.getQueryStr()).thenReturn(queryString); 144 | when(stream.getName()).thenReturn(name); 145 | TicketChecker ticketChecker = new TicketChecker("Stream", ticketTool); 146 | // Test 147 | boolean result = ticketChecker.checkTicket(stream, stream.getClient()); 148 | // Validate 149 | assertFalse(result, "Expected not to be allowed"); 150 | } 151 | 152 | private Ticket getTicket(String username, String resource) { 153 | Ticket ticket = new Ticket("Stream", username, Arrays.asList(resource), new HashMap>()); 154 | return ticket; 155 | } 156 | } 157 | -------------------------------------------------------------------------------- /wowza-ticket-checker-module/src/test/java/dk/statsbiblioteket/medieplatform/wowza/plugin/ticket/TicketToolTest.java: -------------------------------------------------------------------------------- 1 | package dk.statsbiblioteket.medieplatform.wowza.plugin.ticket; 2 | 3 | 4 | import static org.junit.jupiter.api.Assertions.assertEquals; 5 | 6 | import java.util.ArrayList; 7 | import java.util.Arrays; 8 | import java.util.List; 9 | import java.util.Map; 10 | 11 | import javax.ws.rs.core.MediaType; 12 | 13 | import org.apache.cxf.jaxrs.client.WebClient; 14 | import org.junit.jupiter.api.AfterEach; 15 | import org.junit.jupiter.api.BeforeEach; 16 | import org.junit.jupiter.api.Disabled; 17 | import org.junit.jupiter.api.Test; 18 | 19 | import com.fasterxml.jackson.jaxrs.json.JacksonJaxbJsonProvider; 20 | import com.wowza.wms.logging.WMSLogger; 21 | import com.wowza.wms.logging.WMSLoggerFactory; 22 | 23 | import dk.statsbiblioteket.medieplatform.ticketsystem.Property; 24 | 25 | public class TicketToolTest { 26 | 27 | private WMSLogger logger; 28 | private static final String TICKET_SERVICE_URL = "http://iapetus.statsbiblioteket.dk:9651/ticket-system-service/tickets"; 29 | 30 | public TicketToolTest() { 31 | super(); 32 | this.logger = WMSLoggerFactory.getLogger(this.getClass()); 33 | } 34 | 35 | @BeforeEach 36 | public void setUp() throws Exception { 37 | org.apache.log4j.BasicConfigurator.configure(); 38 | } 39 | 40 | @AfterEach 41 | public void tearDown() throws Exception { 42 | org.apache.log4j.BasicConfigurator.resetConfiguration(); 43 | } 44 | 45 | /* 46 | * Test that is for internal use only, requires access to infrasture not reachable from the internet. 47 | * Can be used to verify that tickets can be requested and validated. 48 | */ 49 | @Test 50 | //@Disabled 51 | public void testValidateTicket() { 52 | // Setup environment 53 | TicketToolInterface ticketTool = new TicketTool(TICKET_SERVICE_URL, logger); 54 | String username = "172.18.98.246"; //aUsername"; 55 | String url = "doms_radioTVCollection:uuid:371157ee-b120-4504-bfaf-364c15a4137c"; 56 | Map ticketMap = issueTicket(username, url, Arrays.asList(new Property("SBIPRoleMapper", "inhouse"))); 57 | String issuedTicketId = null; 58 | for (String key : ticketMap.keySet()) { 59 | issuedTicketId = ticketMap.get(key); 60 | } 61 | logger.debug("Issued ticket: " + issuedTicketId); 62 | dk.statsbiblioteket.medieplatform.ticketsystem.Ticket resolvedTicket = ticketTool.resolveTicket(issuedTicketId); 63 | logger.debug("Resolved ticket: " + resolvedTicket); 64 | assertEquals(url, resolvedTicket.getResources().get(0)); 65 | assertEquals(username, resolvedTicket.getIpAddress()); 66 | 67 | } 68 | 69 | private Map issueTicket(String username, String resource, List properties) { 70 | List providers = new ArrayList<>(); 71 | providers.add(new JacksonJaxbJsonProvider()); 72 | WebClient client = WebClient.create(TICKET_SERVICE_URL, providers); 73 | WebClient clientRequest = client.path("/issueTicket") 74 | .query("ipAddress", username) 75 | .query("id", resource) 76 | .query("resource", resource) 77 | .query("type","Stream"); 78 | for (Property prop : properties) { 79 | clientRequest = clientRequest.query(prop.getName(), prop.getValue()); 80 | } 81 | Map resp = clientRequest.accept(MediaType.APPLICATION_JSON).post(null, Map.class); 82 | return resp; 83 | } 84 | 85 | } 86 | --------------------------------------------------------------------------------